This script is very similar to degree_shifts. However, I am calculating area from polygons instead of raster::area of rasters to see how accurate the calculations are.

Degree shifts

Second part of paper, if we move away from equator by 1˚ degree, how much habitat do we gain or lost

I need to look at shelf area by degrees latitude

library(raster)
library(sf)
library(ncdf4)
library(rmapshaper)
library(tidyverse)
library(diptest)
library(moments)
library(viridis) #colors
library(data.table)
library(hydroTSM) #hypsometric curves
library(gridExtra)
library(maptools)
library(rgdal)
library(rgeos)
library(SpaDES)
library(rnaturalearth)
library(rnaturalearthdata)


etopo_shelf_df <- readRDS("~/Documents/grad school/Rutgers/Repositories/shelf_habitat_distribution/etopo_shelf_df.rds")
#bring in bathymetry data frame for shelf regions

#LMEs
LME_spdf <- readOGR("LME66/LMEs66.shp") #spatial points data frame with all 66 LMEs


#convert to equal area projection
#equalareaprojection<- crs(" +proj=eqearth ")

#The Lambert azimuthal equal-area projection is a particular mapping from a sphere to a disk. It accurately represents area in all regions of the sphere, but it does not accurately represent angles.
equalareaprojection<- crs(" +proj=laea ")

Make bathymetry data frame into raster (this takes a bit)

Note that I am trying to use the equal area projection


etopo_shelf_raster <- rasterFromXYZ(etopo_shelf_df, crs = crs(LME_spdf))

#reclassify all values <2000m in depth to 1 instead of actual depth
etopo_shelf_raster<- reclassify(etopo_shelf_raster,cbind(-Inf, Inf, 1))

Should go by projections of where species are moving: “Marine species (~80% being ectotherms in the database; Extended Data Fig. 2) have moved towards the poles at a mean (±s.e.m.) pace of 5.92 ± 0.94 km yr−1 (one-sample Student’s t-test: t=6.26; d.f. residuals=23; P=2.20×10–6), which is almost six times faster than terrestrial species (one-way analysis of variance (ANOVA): F=12.68; d.f. factor=1; d.f. residuals=45; P=8.88×10–4).” Lenoir 2020

5.92 km * 10 = 59.2 km in 10 years

59.2 km is how many degrees?

1° = 111 km

so,

59.2/111*1

0.5333˚ is representative of decadal shifts, but, for better visualization let’s go with 1˚ (representative of 20 year shifts)

I will put areas into 1˚ Bins (180 total degrees, so 180/1=180 total latitudinal bins)

180/1

How does continental shelf habitat change with latitude?

Look at contiguous coast lines.

I am going to leave out Antarctica (61) and the Arctic (64) as Antarctica drowned out patterns in lower latitudes and Arctic doesn’t have much habitat shallower than 2000m to begin with.

Eastern Atlantic (3) -19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 58, 59, 60, 62

Western Atlantic (2) - 5, 6, 7, 8, 9, 12, 14, 15, 16, 17, 18, 63, 66

Eastern Pacific (1) - 1, 2, 3, 4, 11, 13, 54, 55, 65

Western Indian (4) -30, 31, 32, 33

Eastern Indian (5) -34, 38, 43, 44, 45

Western Pacific (6) 1, 35, 36, 37, 39, 40, 41, 42, 46, 47, 48, 49, 50, 51, 52, 53, 54, 56, 57, 65

Merge LMEs into 6 coastline regions

west_pac <- c(1,    35, 36, 37, 39, 40, 41, 42, 46, 47, 48, 49, 50, 51, 52, 53, 54, 56, 57, 65)
east_pac <- c(1, 2, 3, 4, 11, 13, 54, 55, 65)
west_atl <- c(5, 6, 7, 8, 9, 12, 14, 15, 16, 17, 18, 63, 66)
east_atl <- c(19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 58, 59, 60, 62)
west_ind <- c(30, 31, 32, 33)
east_ind <- c(34, 38, 43, 44, 45)

#subregions based on LME_number
west_pac_spdf <- LME_spdf[(LME_spdf$LME_NUMBER) %in% west_pac,]
east_pac_spdf <- LME_spdf[(LME_spdf$LME_NUMBER) %in% east_pac,]
west_atl_spdf <- LME_spdf[(LME_spdf$LME_NUMBER) %in% west_atl,]
west_ind_spdf <- LME_spdf[(LME_spdf$LME_NUMBER) %in% west_ind,]
east_atl_spdf <- LME_spdf[(LME_spdf$LME_NUMBER) %in% east_atl,]
east_ind_spdf <- LME_spdf[(LME_spdf$LME_NUMBER) %in% east_ind,]

#for subregions that span 360, we need to change CRS a bit
newCRS_west <- "+proj=longlat +datum=WGS84 +lon_wrap=180" #this shifts 180 degrees
west_pac_spdf_shift <- spTransform(west_pac_spdf, CRS(newCRS_west))
west_pac_spdf_shift <- gBuffer(west_pac_spdf_shift, byid=TRUE, width=0) #gets rid of buffers, allows for union

newCRS_east <- "+proj=longlat +datum=WGS84 +lon_wrap=180" #this shifts 180 degrees
east_pac_spdf_shift <- spTransform(east_pac_spdf, CRS(newCRS_east))
east_pac_spdf_shift <- gBuffer(east_pac_spdf_shift, byid=TRUE, width=0) #gets rid of buffers, allows for union

#rotate raster for bathymetry (guided by extent of etoposhelf raster,  that's why wacky #s)
x1 <- crop(etopo_shelf_raster, extent(-180.0167, -0.0167, -90.01667, 90.01667))
x2 <- crop(etopo_shelf_raster, extent(0, 180.0167, -90.01667, 90.01667))   
extent(x1) <- c(180.0167, 360.0167, -90.01667 , 90.01667)
etopo_shelf_raster_180 <- merge(x1, x2)

#get rid of buffer for east atl as well to allow for union

east_atl_spdf_nobuf <- gBuffer(east_atl_spdf, byid=TRUE, width=0)

region_names <- c("west_pac_spdf_shift", "east_pac_spdf_shift", "west_atl_spdf", "west_ind_spdf", "east_atl_spdf_nobuf", "east_ind_spdf")



#dissolve all polygons by region
for (i in 1:length(region_names)) {
  name <- paste0(region_names[i], "_agg")
  assign(name, gUnaryUnion(get(region_names[i]))) #dissolve polygons within coastline region into one
}

Extract bathymetry data from polygon only to make sure we’re limiting to shelf regions above 2000 meters

How to calculate area?

Now, we will split each coastline raster into latitudinal bins of 1˚

Western Pacific

north_extent <- c(xmin(west_pac_spdf_shift_mask_1s), xmax(west_pac_spdf_shift_mask_1s), 0, ymax(west_pac_spdf_shift_mask_1s))
south_extent <- c(xmin(west_pac_spdf_shift_mask_1s), xmax(west_pac_spdf_shift_mask_1s), ymin(west_pac_spdf_shift_mask_1s), 0)

#crop west_pac raster above and below 0
west_pac_spdf_shift_agg_north <- crop(west_pac_spdf_shift_mask_1s, extent(north_extent))

west_pac_spdf_shift_agg_south <- crop(west_pac_spdf_shift_mask_1s, extent(south_extent))

#unfortunately, I think I may have to just do this manually (ugly, I know)

#all chunks for west pacific
west_pac_north_latitudes <- seq(0, ymax(west_pac_spdf_shift_mask_1s), by = 1)
west_pac_south_latitudes <- seq(0, ymin(west_pac_spdf_shift_mask_1s), by = -1)

#setup data table to populate in loop, subtracting one to allow for bins
west_pac_shelf_areas <- as.data.table(matrix(nrow = (length(west_pac_north_latitudes)-1+length(west_pac_south_latitudes)-1)))
                                      
west_pac_shelf_areas[, latitude_start := as.numeric(V1)][, latitude_end := as.numeric(V1)][, area_rasterarea := as.numeric(V1)][, area_equalareaproj := as.numeric(V1)][, area_rgeos_gArea := as.numeric(V1)][, V1 := NULL]

#loop for north
for (i in 1:(length(west_pac_north_latitudes)-1)) {
  #setting up extent for slicing by min and max longitudes, and i to i+1 latitudes
  north_extent <- c(xmin(west_pac_spdf_shift_mask_1s), xmax(west_pac_spdf_shift_mask_1s), west_pac_north_latitudes[i], west_pac_north_latitudes[i+1])
  
  #crop raster segement based on bin extent
  segment_north <- crop(west_pac_spdf_shift_mask_1s, extent(north_extent))
  
  #populate data table with latitudinal bin
  west_pac_shelf_areas[i, "latitude_start"] <- west_pac_north_latitudes[i]
  west_pac_shelf_areas[i, "latitude_end"] <- west_pac_north_latitudes[i+1]
  
  if(all(is.na(values(segment_north)))) { #if there's no shelf area within a bin, all area = 0
    
  west_pac_shelf_areas[i, "area_equalareaproj"] <- 0
  west_pac_shelf_areas[i, "area_rasterarea"] <- 0
  west_pac_shelf_areas[i, "area_rgeos_gArea"] <- 0

  
  print(i)
    
  } else { #if there is shelf area within the bin, calculate area of slice
  
    #raster area calculation
      #get sizes of all cells in raster [km2]
    cell_size_raster<-area(segment_north, na.rm=TRUE, weights=FALSE)
    
    #delete NAs from vector of all raster cells
    cell_size_raster<-cell_size_raster[!is.na(segment_north)]
    
    #compute area of all cells in geo_raster
    #full area          <- total # grid cells     * median cell area (using median cares less about extreme values)
    segment_area_raster <- length(cell_size_raster)*median(cell_size_raster) #in km^2
    
  #populate data table with raster area
  west_pac_shelf_areas[i, "area_rasterarea"] <- segment_area_raster
    
  #convert to spatial polygons to check area calculations
    
  #convert segment from raster to polygon, each cell from the raster is an independent polygon, (dissolve means all cells with a value of 1 are a single polygon if connected)
  segment_north.sp <- rasterToPolygons(segment_north, dissolve = T)
  
  #  If x is a SpatialPolygons* object: area of each spatial object in squared meters if the CRS is longitude/latitude, or in squared map units (typically meter)
  
    #project to equal earth area projection
  segment_north.sp.EA <- spTransform(segment_north.sp, CRSobj = equalareaprojection)

  #calculate area of the spatial object in m^2
    polygon_size.sp <- area(segment_north.sp.EA)

    #convert from m^2 to km^2
    segment_area_equalarea <- polygon_size.sp/1e6

    #populate data table with polygon area using raster calculation
  west_pac_shelf_areas[i, "area_equalareaproj"] <- segment_area_equalarea
  
  #and then plain and simple also using rgeos::gArea
  
  area_rgeos_gArea <- gArea(segment_north.sp.EA)/1e6
  
  #populate data table with polygon area using regeos calculation
  west_pac_shelf_areas[i, "area_rgeos_gArea"] <-   area_rgeos_gArea
  
  print(i)
  } 
}

#loop for south
for (i in 1:(length(west_pac_south_latitudes)-1)) {
  south_extent <- c(xmin(west_pac_spdf_shift_mask_1s), xmax(west_pac_spdf_shift_mask_1s), west_pac_south_latitudes[i+1], west_pac_south_latitudes[i]) #order= xmin, xmax, ymin, ymax)
  
  #raster segment
  segment_south <- crop(west_pac_spdf_shift_mask_1s, extent(south_extent))
  
  #add latitude bin info to data table
    west_pac_shelf_areas[i+(length(west_pac_north_latitudes)-1), "latitude_start"] <- west_pac_south_latitudes[i]
  west_pac_shelf_areas[i+(length(west_pac_north_latitudes)-1), "latitude_end"] <- west_pac_south_latitudes[i+1]
  
  
  if(all(is.na(values(segment_south)))) { #if there's no shelf area within a bin, meaning there's no shelf area at that latitude
    
  west_pac_shelf_areas[i+(length(west_pac_north_latitudes)-1), "area_equalareaproj"] <- 0
  west_pac_shelf_areas[i+(length(west_pac_north_latitudes)-1), "area_rasterarea"] <- 0
    west_pac_shelf_areas[i+(length(west_pac_north_latitudes)-1), "area_rgeos_gArea"] <- 0
  
  print(i)
    
  } else {
  
    #raster area calculation
      #get sizes of all cells in raster [km2]
    cell_size_raster<-area(segment_south, na.rm=TRUE, weights=FALSE)
    
    #delete NAs from vector of all raster cells
    cell_size_raster<-cell_size_raster[!is.na(segment_south)]
    #compute area of all cells in geo_raster
    #full area          <- total # grid cells     * median cell area (using median cares less about extreme values)
    segment_area_raster <- length(cell_size_raster)*median(cell_size_raster)
    
  #populate data table with raster area
  west_pac_shelf_areas[i+(length(west_pac_north_latitudes)-1), "area_rasterarea"] <- segment_area_raster
    
  
  #convert to spatial polygons to check area calculations
    
  #convert segment from raster to polygon, each cell from the raster is an independent polygon, (dissolve means all cells with a value of 1 are a single polygon if connected)
  segment_south.sp <- rasterToPolygons(segment_south, dissolve = T)
  
  #  If x is a SpatialPolygons* object: area of each spatial object in squared meters if the CRS is longitude/latitude, or in squared map units (typically meter)
  
    #project to equal earth area projection
  segment_south.sp.EA <- spTransform(segment_south.sp, CRSobj = equalareaprojection)

  #calculate area of the spatial object in m^2
    polygon_size.sp <- area(segment_south.sp.EA)

    #convert from m^2 to km^2
    segment_area_equalarea <- polygon_size.sp/1e6

    #populate data table with area of polygon from raster::area function
  west_pac_shelf_areas[i+(length(west_pac_north_latitudes)-1), "area_equalareaproj"] <- segment_area_equalarea
  
  #and then plain and simple also using rgeos::gArea
  
  area_rgeos_gArea <- gArea(segment_south.sp.EA)/1e6
  
  #populate data table from rgeos area calculation for projected polygon
  west_pac_shelf_areas[i+(length(west_pac_north_latitudes)-1), "area_rgeos_gArea"] <-   area_rgeos_gArea
  
  print(i)
  } 
}

#compare raster:area calculation, to equal area still using raster::area function, to rgeos::gArea function for polygons

ggplot(data = west_pac_shelf_areas) +
  geom_point(aes(x = latitude_start, y = area_rgeos_gArea), color = "purple", size = 0.5) +
  geom_point(aes(x = latitude_start, y = area_rasterarea), color = "darkgreen", size = 0.5) +
  geom_point(aes(x = latitude_start, y = area_equalareaproj), color = "red", size = 0.5) +
  labs(x = "Latitude", y = "Area km^2") +
  theme_classic()

cor(west_pac_shelf_areas[,3:5], use = "complete.obs")

save(west_pac_shelf_areas, file = "west_pac_shelf_areas.RData")

Classify by percent change!!

between 1 and Inf % change = at least 2 fold increase (note I classified any change from 0 to something as NOT a significant change, should return to this conceptually)

between -0.5 and -inf % change = at least 2 fold decrease

between -0.499 and 0.999 = no significant change

For area metric here, I used the raster::area function applied to the projected shapefile

west_pac_shelf_areas[, percent_change := (area_equalareaproj-shift(area_equalareaproj, type = "lag"))/shift(area_equalareaproj, type = "lag")][,area_1000s := area_equalareaproj/1000]

west_pac_shelf_areas[, change_above_2fold := ifelse((percent_change>=1 & percent_change<Inf), 1, ifelse(percent_change<=-0.5, -1, 0))]

west_pac_shelf_areas_highlight <- west_pac_shelf_areas[change_above_2fold != 0,]

west_pac_shelf_areas_stats <- table(west_pac_shelf_areas[,.(change_above_2fold)])

Eastern Pacific

east_pac_spdf_shift

save(east_pac_shelf_areas, "east_pac_shelf_areas.RData")
Error in save(east_pac_shelf_areas, "east_pac_shelf_areas.RData") : 
  object ‘east_pac_shelf_areas.RData’ not found
east_pac_shelf_areas[, percent_change := (area_equalareaproj-shift(area_equalareaproj, type = "lag"))/shift(area_equalareaproj, type = "lag")][,area_1000s := area_equalareaproj/1000]

east_pac_shelf_areas[, change_above_2fold := ifelse((percent_change>=1 & percent_change<Inf), 1, ifelse(percent_change<=-0.5, -1, 0))]

east_pac_shelf_areas_highlight <- east_pac_shelf_areas[change_above_2fold != 0,]

east_pac_shelf_areas_stats <- table(east_pac_shelf_areas[,.(change_above_2fold)])

Western Atlantic

west_atl_spdf_mask

north_extent <- c(xmin(west_atl_spdf_mask_1s), xmax(west_atl_spdf_mask_1s), 0, ymax(west_atl_spdf_mask_1s))
south_extent <- c(xmin(west_atl_spdf_mask_1s), xmax(west_atl_spdf_mask_1s), ymin(west_atl_spdf_mask_1s), 0)

#crop west_atl raster above and below 0
west_atl_spdf_shift_agg_north <- crop(west_atl_spdf_mask_1s, extent(north_extent))

west_atl_spdf_shift_agg_south <- crop(west_atl_spdf_mask_1s, extent(south_extent))

#unfortunately, I think I may have to just do this manually (ugly, I know)

#all chunks for west atlantic
west_atl_north_latitudes <- seq(0, ymax(west_atl_spdf_mask_1s), by = 1)
west_atl_south_latitudes <- seq(0, ymin(west_atl_spdf_mask_1s), by = -1)

#setup data table to populate in loop, subtracting one to allow for bins
west_atl_shelf_areas <- as.data.table(matrix(nrow = (length(west_atl_north_latitudes)-1+length(west_atl_south_latitudes)-1)))
                                      
west_atl_shelf_areas[, latitude_start := as.numeric(V1)][, latitude_end := as.numeric(V1)][, area_rasterarea := as.numeric(V1)][, area_equalareaproj := as.numeric(V1)][, area_rgeos_gArea := as.numeric(V1)][, V1 := NULL]

#loop for north
for (i in 1:(length(west_atl_north_latitudes)-1)) {
  #setting up extent for slicing by min and max longitudes, and i to i+1 latitudes
  north_extent <- c(xmin(west_atl_spdf_mask_1s), xmax(west_atl_spdf_mask_1s), west_atl_north_latitudes[i], west_atl_north_latitudes[i+1])
  
  #crop raster segement based on bin extent
  segment_north <- crop(west_atl_spdf_mask_1s, extent(north_extent))
  
  #populate data table with latitudinal bin
  west_atl_shelf_areas[i, "latitude_start"] <- west_atl_north_latitudes[i]
  west_atl_shelf_areas[i, "latitude_end"] <- west_atl_north_latitudes[i+1]
  
  if(all(is.na(values(segment_north)))) { #if there's no shelf area within a bin, all area = 0
    
  west_atl_shelf_areas[i, "area_equalareaproj"] <- 0
  west_atl_shelf_areas[i, "area_rasterarea"] <- 0
  west_atl_shelf_areas[i, "area_rgeos_gArea"] <- 0

  
  print(i)
    
  } else { #if there is shelf area within the bin, calculate area of slice
  
    #raster area calculation
      #get sizes of all cells in raster [km2]
    cell_size_raster<-area(segment_north, na.rm=TRUE, weights=FALSE)
    
    #delete NAs from vector of all raster cells
    cell_size_raster<-cell_size_raster[!is.na(segment_north)]
    
    #compute area of all cells in geo_raster
    #full area          <- total # grid cells     * median cell area (using median cares less about extreme values)
    segment_area_raster <- length(cell_size_raster)*median(cell_size_raster) #in km^2
    
  #populate data table with raster area
  west_atl_shelf_areas[i, "area_rasterarea"] <- segment_area_raster
    
  #convert to spatial polygons to check area calculations
    
  #convert segment from raster to polygon, each cell from the raster is an independent polygon, (dissolve means all cells with a value of 1 are a single polygon if connected)
  segment_north.sp <- rasterToPolygons(segment_north, dissolve = T)
  
  #  If x is a SpatialPolygons* object: area of each spatial object in squared meters if the CRS is longitude/latitude, or in squared map units (typically meter)
  
    #project to equal earth area projection
  segment_north.sp.EA <- spTransform(segment_north.sp, CRSobj = equalareaprojection)

  #calculate area of the spatial object in m^2
    polygon_size.sp <- area(segment_north.sp.EA)

    #convert from m^2 to km^2
    segment_area_equalarea <- polygon_size.sp/1e6

    #populate data table with polygon area using raster calculation
  west_atl_shelf_areas[i, "area_equalareaproj"] <- segment_area_equalarea
  
  #and then plain and simple also using rgeos::gArea
  
  area_rgeos_gArea <- gArea(segment_north.sp.EA)/1e6
  
  #populate data table with polygon area using regeos calculation
  west_atl_shelf_areas[i, "area_rgeos_gArea"] <-   area_rgeos_gArea
  
  print(i)
  } 
}
[1] 1
[1] 2
[1] 3
[1] 4
[1] 5
[1] 6
[1] 7
[1] 8
[1] 9
[1] 10
[1] 11
[1] 12
[1] 13
[1] 14
[1] 15
[1] 16
[1] 17
[1] 18
[1] 19
[1] 20
[1] 21
[1] 22
[1] 23
[1] 24
[1] 25
[1] 26
[1] 27
[1] 28
[1] 29
[1] 30
[1] 31
[1] 32
[1] 33
[1] 34
[1] 35
[1] 36
[1] 37
[1] 38
[1] 39
[1] 40
[1] 41
[1] 42
[1] 43
[1] 44
[1] 45
[1] 46
[1] 47
[1] 48
[1] 49
[1] 50
[1] 51
[1] 52
[1] 53
[1] 54
[1] 55
[1] 56
[1] 57
[1] 58
[1] 59
[1] 60
[1] 61
[1] 62
[1] 63
[1] 64
[1] 65
[1] 66
[1] 67
[1] 68
[1] 69
[1] 70
[1] 71
[1] 72
[1] 73
[1] 74
[1] 75
[1] 76
[1] 77
[1] 78
[1] 79
[1] 80
[1] 81
[1] 82
[1] 83
[1] 84
#loop for south
for (i in 1:(length(west_atl_south_latitudes)-1)) {
  south_extent <- c(xmin(west_atl_spdf_mask_1s), xmax(west_atl_spdf_mask_1s), west_atl_south_latitudes[i+1], west_atl_south_latitudes[i]) #order= xmin, xmax, ymin, ymax)
  
  #raster segment
  segment_south <- crop(west_atl_spdf_mask_1s, extent(south_extent))
  
  #add latitude bin info to data table
    west_atl_shelf_areas[i+(length(west_atl_north_latitudes)-1), "latitude_start"] <- west_atl_south_latitudes[i]
  west_atl_shelf_areas[i+(length(west_atl_north_latitudes)-1), "latitude_end"] <- west_atl_south_latitudes[i+1]
  
  
  if(all(is.na(values(segment_south)))) { #if there's no shelf area within a bin, meaning there's no shelf area at that latitude

  west_atl_shelf_areas[i+(length(west_atl_north_latitudes)-1), "area_equalareaproj"] <- 0
  west_atl_shelf_areas[i+(length(west_atl_north_latitudes)-1), "area_rasterarea"] <- 0
    west_atl_shelf_areas[i+(length(west_atl_north_latitudes)-1), "area_rgeos_gArea"] <- 0
  
  print(i)
    
  } else {
  
    #raster area calculation
      #get sizes of all cells in raster [km2]
    cell_size_raster<-area(segment_south, na.rm=TRUE, weights=FALSE)
    
    #delete NAs from vector of all raster cells
    cell_size_raster<-cell_size_raster[!is.na(segment_south)]
    #compute area of all cells in geo_raster
    #full area          <- total # grid cells     * median cell area (using median cares less about extreme values)
    segment_area_raster <- length(cell_size_raster)*median(cell_size_raster)
    
  #populate data table with raster area
  west_atl_shelf_areas[i+(length(west_atl_north_latitudes)-1), "area_rasterarea"] <- segment_area_raster
    
  
  #convert to spatial polygons to check area calculations
    
  #convert segment from raster to polygon, each cell from the raster is an independent polygon, (dissolve means all cells with a value of 1 are a single polygon if connected)
  segment_south.sp <- rasterToPolygons(segment_south, dissolve = T)
  
  #  If x is a SpatialPolygons* object: area of each spatial object in squared meters if the CRS is longitude/latitude, or in squared map units (typically meter)
  
    #project to equal earth area projection
  segment_south.sp.EA <- spTransform(segment_south.sp, CRSobj = equalareaprojection)

  #calculate area of the spatial object in m^2
    polygon_size.sp <- area(segment_south.sp.EA)

    #convert from m^2 to km^2
    segment_area_equalarea <- polygon_size.sp/1e6

    #populate data table with area of polygon from raster::area function
  west_atl_shelf_areas[i+(length(west_atl_north_latitudes)-1), "area_equalareaproj"] <- segment_area_equalarea
  
  #and then plain and simple also using rgeos::gArea
  
  area_rgeos_gArea <- gArea(segment_south.sp.EA)/1e6
  
  #populate data table from rgeos area calculation for projected polygon
  west_atl_shelf_areas[i+(length(west_atl_north_latitudes)-1), "area_rgeos_gArea"] <-   area_rgeos_gArea
  
  print(i)
  } 
}
[1] 1
[1] 2
[1] 3
[1] 4
[1] 5
[1] 6
[1] 7
[1] 8
[1] 9
[1] 10
[1] 11
[1] 12
[1] 13
[1] 14
[1] 15
[1] 16
[1] 17
[1] 18
[1] 19
[1] 20
[1] 21
[1] 22
[1] 23
[1] 24
[1] 25
[1] 26
[1] 27
[1] 28
[1] 29
[1] 30
[1] 31
[1] 32
[1] 33
[1] 34
[1] 35
[1] 36
[1] 37
[1] 38
[1] 39
[1] 40
[1] 41
[1] 42
[1] 43
[1] 44
[1] 45
[1] 46
[1] 47
[1] 48
[1] 49
[1] 50
[1] 51
[1] 52
[1] 53
[1] 54
[1] 55
#compare raster:area calculation, to equal area still using raster::area function, to rgeos::gArea function for polygons

ggplot(data = west_atl_shelf_areas) +
  geom_point(aes(x = latitude_start, y = area_rgeos_gArea), color = "purple", size = 0.5) +
  geom_point(aes(x = latitude_start, y = area_rasterarea), color = "darkgreen", size = 0.5) +
  geom_point(aes(x = latitude_start, y = area_equalareaproj), color = "red", size = 0.5) +
  labs(x = "Latitude", y = "Area km^2") +
  theme_classic()


cor(west_atl_shelf_areas[,3:5], use = "complete.obs")
                   area_rasterarea area_equalareaproj area_rgeos_gArea
area_rasterarea          1.0000000          0.9999914        0.9999914
area_equalareaproj       0.9999914          1.0000000        1.0000000
area_rgeos_gArea         0.9999914          1.0000000        1.0000000
west_atl_shelf_areas[, percent_change := (area_equalareaproj-shift(area_equalareaproj, type = "lag"))/shift(area_equalareaproj, type = "lag")][,area_1000s := area_equalareaproj/1000]

west_atl_shelf_areas[, change_above_2fold := ifelse((percent_change>=1 & percent_change<Inf), 1, ifelse(percent_change<=-0.5, -1, 0))]

west_atl_shelf_areas_highlight <- west_atl_shelf_areas[change_above_2fold != 0,]

west_atl_shelf_areas_stats <- table(west_atl_shelf_areas[,.(change_above_2fold)])

Eastern Atlantic

east_atl_spdf_nobuf_mask

north_extent <- c(xmin(east_atl_spdf_nobuf_mask_1s), xmax(east_atl_spdf_nobuf_mask_1s), 0, ymax(east_atl_spdf_nobuf_mask_1s))
south_extent <- c(xmin(east_atl_spdf_nobuf_mask_1s), xmax(east_atl_spdf_nobuf_mask_1s), ymin(east_atl_spdf_nobuf_mask_1s), 0)

#crop east_atl raster above and below 0
east_atl_spdf_shift_agg_north <- crop(east_atl_spdf_nobuf_mask_1s, extent(north_extent))

east_atl_spdf_shift_agg_south <- crop(east_atl_spdf_nobuf_mask_1s, extent(south_extent))

#unfortunately, I think I may have to just do this manually (ugly, I know)

#all chunks for east atlantic
east_atl_north_latitudes <- seq(0, ymax(east_atl_spdf_nobuf_mask_1s), by = 1)
east_atl_south_latitudes <- seq(0, ymin(east_atl_spdf_nobuf_mask_1s), by = -1)

#setup data table to populate in loop, subtracting one to allow for bins
east_atl_shelf_areas <- as.data.table(matrix(nrow = (length(east_atl_north_latitudes)-1+length(east_atl_south_latitudes)-1)))
                                      
east_atl_shelf_areas[, latitude_start := as.numeric(V1)][, latitude_end := as.numeric(V1)][, area_rasterarea := as.numeric(V1)][, area_equalareaproj := as.numeric(V1)][, area_rgeos_gArea := as.numeric(V1)][, V1 := NULL]

#loop for north
for (i in 1:(length(east_atl_north_latitudes)-1)) {
  #setting up extent for slicing by min and max longitudes, and i to i+1 latitudes
  north_extent <- c(xmin(east_atl_spdf_nobuf_mask_1s), xmax(east_atl_spdf_nobuf_mask_1s), east_atl_north_latitudes[i], east_atl_north_latitudes[i+1])
  
  #crop raster segement based on bin extent
  segment_north <- crop(east_atl_spdf_nobuf_mask_1s, extent(north_extent))
  
  #populate data table with latitudinal bin
  east_atl_shelf_areas[i, "latitude_start"] <- east_atl_north_latitudes[i]
  east_atl_shelf_areas[i, "latitude_end"] <- east_atl_north_latitudes[i+1]
  
  if(all(is.na(values(segment_north)))) { #if there's no shelf area within a bin, all area = 0
    
  east_atl_shelf_areas[i, "area_equalareaproj"] <- 0
  east_atl_shelf_areas[i, "area_rasterarea"] <- 0
  east_atl_shelf_areas[i, "area_rgeos_gArea"] <- 0

  
  print(i)
    
  } else { #if there is shelf area within the bin, calculate area of slice
  
    #raster area calculation
      #get sizes of all cells in raster [km2]
    cell_size_raster<-area(segment_north, na.rm=TRUE, weights=FALSE)
    
    #delete NAs from vector of all raster cells
    cell_size_raster<-cell_size_raster[!is.na(segment_north)]
    
    #compute area of all cells in geo_raster
    #full area          <- total # grid cells     * median cell area (using median cares less about extreme values)
    segment_area_raster <- length(cell_size_raster)*median(cell_size_raster) #in km^2
    
  #populate data table with raster area
  east_atl_shelf_areas[i, "area_rasterarea"] <- segment_area_raster
    
  #convert to spatial polygons to check area calculations
    
  #convert segment from raster to polygon, each cell from the raster is an independent polygon, (dissolve means all cells with a value of 1 are a single polygon if connected)
  segment_north.sp <- rasterToPolygons(segment_north, dissolve = T)
  
  #  If x is a SpatialPolygons* object: area of each spatial object in squared meters if the CRS is longitude/latitude, or in squared map units (typically meter)
  
    #project to equal earth area projection
  segment_north.sp.EA <- spTransform(segment_north.sp, CRSobj = equalareaprojection)

  #calculate area of the spatial object in m^2
    polygon_size.sp <- area(segment_north.sp.EA)

    #convert from m^2 to km^2
    segment_area_equalarea <- polygon_size.sp/1e6

    #populate data table with polygon area using raster calculation
  east_atl_shelf_areas[i, "area_equalareaproj"] <- segment_area_equalarea
  
  #and then plain and simple also using rgeos::gArea
  
  area_rgeos_gArea <- gArea(segment_north.sp.EA)/1e6
  
  #populate data table with polygon area using regeos calculation
  east_atl_shelf_areas[i, "area_rgeos_gArea"] <-   area_rgeos_gArea
  
  print(i)
  } 
}
[1] 1
[1] 2
[1] 3
[1] 4
[1] 5
[1] 6
[1] 7
[1] 8
[1] 9
[1] 10
[1] 11
[1] 12
[1] 13
[1] 14
[1] 15
[1] 16
[1] 17
[1] 18
[1] 19
[1] 20
[1] 21
[1] 22
[1] 23
[1] 24
[1] 25
[1] 26
[1] 27
[1] 28
[1] 29
[1] 30
[1] 31
[1] 32
[1] 33
[1] 34
[1] 35
[1] 36
[1] 37
[1] 38
[1] 39
[1] 40
[1] 41
[1] 42
[1] 43
[1] 44
[1] 45
[1] 46
[1] 47
[1] 48
[1] 49
[1] 50
[1] 51
[1] 52
[1] 53
[1] 54
[1] 55
[1] 56
[1] 57
[1] 58
[1] 59
[1] 60
[1] 61
[1] 62
[1] 63
[1] 64
[1] 65
[1] 66
[1] 67
[1] 68
[1] 69
[1] 70
[1] 71
[1] 72
[1] 73
[1] 74
[1] 75
[1] 76
[1] 77
[1] 78
[1] 79
[1] 80
[1] 81
[1] 82
#loop for south
for (i in 1:(length(east_atl_south_latitudes)-1)) {
  south_extent <- c(xmin(east_atl_spdf_nobuf_mask_1s), xmax(east_atl_spdf_nobuf_mask_1s), east_atl_south_latitudes[i+1], east_atl_south_latitudes[i]) #order= xmin, xmax, ymin, ymax)
  
  #raster segment
  segment_south <- crop(east_atl_spdf_nobuf_mask_1s, extent(south_extent))
  
  #add latitude bin info to data table
    east_atl_shelf_areas[i+(length(east_atl_north_latitudes)-1), "latitude_start"] <- east_atl_south_latitudes[i]
  east_atl_shelf_areas[i+(length(east_atl_north_latitudes)-1), "latitude_end"] <- east_atl_south_latitudes[i+1]
  
  
  if(all(is.na(values(segment_south)))) { #if there's no shelf area within a bin, meaning there's no shelf area at that latitude

  east_atl_shelf_areas[i+(length(east_atl_north_latitudes)-1), "area_equalareaproj"] <- 0
  east_atl_shelf_areas[i+(length(east_atl_north_latitudes)-1), "area_rasterarea"] <- 0
    east_atl_shelf_areas[i+(length(east_atl_north_latitudes)-1), "area_rgeos_gArea"] <- 0
  
  print(i)
    
  } else {
  
    #raster area calculation
      #get sizes of all cells in raster [km2]
    cell_size_raster<-area(segment_south, na.rm=TRUE, weights=FALSE)
    
    #delete NAs from vector of all raster cells
    cell_size_raster<-cell_size_raster[!is.na(segment_south)]
    #compute area of all cells in geo_raster
    #full area          <- total # grid cells     * median cell area (using median cares less about extreme values)
    segment_area_raster <- length(cell_size_raster)*median(cell_size_raster)
    
  #populate data table with raster area
  east_atl_shelf_areas[i+(length(east_atl_north_latitudes)-1), "area_rasterarea"] <- segment_area_raster
    
  
  #convert to spatial polygons to check area calculations
    
  #convert segment from raster to polygon, each cell from the raster is an independent polygon, (dissolve means all cells with a value of 1 are a single polygon if connected)
  segment_south.sp <- rasterToPolygons(segment_south, dissolve = T)
  
  #  If x is a SpatialPolygons* object: area of each spatial object in squared meters if the CRS is longitude/latitude, or in squared map units (typically meter)
  
    #project to equal earth area projection
  segment_south.sp.EA <- spTransform(segment_south.sp, CRSobj = equalareaprojection)

  #calculate area of the spatial object in m^2
    polygon_size.sp <- area(segment_south.sp.EA)

    #convert from m^2 to km^2
    segment_area_equalarea <- polygon_size.sp/1e6

    #populate data table with area of polygon from raster::area function
  east_atl_shelf_areas[i+(length(east_atl_north_latitudes)-1), "area_equalareaproj"] <- segment_area_equalarea
  
  #and then plain and simple also using rgeos::gArea
  
  area_rgeos_gArea <- gArea(segment_south.sp.EA)/1e6
  
  #populate data table from rgeos area calculation for projected polygon
  east_atl_shelf_areas[i+(length(east_atl_north_latitudes)-1), "area_rgeos_gArea"] <-   area_rgeos_gArea
  
  print(i)
  } 
}
[1] 1
[1] 2
[1] 3
[1] 4
[1] 5
[1] 6
[1] 7
[1] 8
[1] 9
[1] 10
[1] 11
[1] 12
[1] 13
[1] 14
[1] 15
[1] 16
[1] 17
[1] 18
[1] 19
[1] 20
[1] 21
[1] 22
[1] 23
[1] 24
[1] 25
[1] 26
[1] 27
[1] 28
[1] 29
[1] 30
[1] 31
[1] 32
[1] 33
[1] 34
[1] 35
[1] 36
#compare raster:area calculation, to equal area still using raster::area function, to rgeos::gArea function for polygons

ggplot(data = east_atl_shelf_areas) +
  geom_point(aes(x = latitude_start, y = area_rgeos_gArea), color = "purple", size = 0.5) +
  geom_point(aes(x = latitude_start, y = area_rasterarea), color = "darkgreen", size = 0.5) +
  geom_point(aes(x = latitude_start, y = area_equalareaproj), color = "red", size = 0.5) +
  labs(x = "Latitude", y = "Area km^2") +
  theme_classic()


cor(east_atl_shelf_areas[,3:5], use = "complete.obs")
                   area_rasterarea area_equalareaproj area_rgeos_gArea
area_rasterarea          1.0000000          0.9999985        0.9999985
area_equalareaproj       0.9999985          1.0000000        1.0000000
area_rgeos_gArea         0.9999985          1.0000000        1.0000000
east_atl_shelf_areas[, percent_change := (area_equalareaproj-shift(area_equalareaproj, type = "lag"))/shift(area_equalareaproj, type = "lag")][,area_1000s := area_equalareaproj/1000]

east_atl_shelf_areas[, change_above_2fold := ifelse((percent_change>=1 & percent_change<Inf), 1, ifelse(percent_change<=-0.5, -1, 0))]

east_atl_shelf_areas_highlight <- east_atl_shelf_areas[change_above_2fold != 0,]

east_atl_shelf_areas_stats <- table(east_atl_shelf_areas[,.(change_above_2fold)])

Western Indian

west_ind_spdf_mask

ggplot(data = west_ind_shelf_areas) +
  geom_point(aes(x = latitude_start, y = area_rgeos_gArea), color = "purple", size = 0.5) +
  geom_point(aes(x = latitude_start, y = area_rasterarea), color = "darkgreen", size = 0.5) +
  geom_point(aes(x = latitude_start, y = area_equalareaproj), color = "red", size = 0.5) +
  labs(x = "Latitude", y = "Area km^2") +
  theme_classic()

cor(west_ind_shelf_areas[,3:5], use = "complete.obs")
                   area_rasterarea area_equalareaproj area_rgeos_gArea
area_rasterarea          1.0000000          0.9999996        0.9999996
area_equalareaproj       0.9999996          1.0000000        1.0000000
area_rgeos_gArea         0.9999996          1.0000000        1.0000000
west_ind_shelf_areas[, percent_change := (area_equalareaproj-shift(area_equalareaproj, type = "lag"))/shift(area_equalareaproj, type = "lag")][,area_1000s := area_equalareaproj/1000]

west_ind_shelf_areas[, change_above_2fold := ifelse((percent_change>=1 & percent_change<Inf), 1, ifelse(percent_change<=-0.5, -1, 0))]

west_ind_shelf_areas_highlight <- west_ind_shelf_areas[change_above_2fold != 0,]

west_ind_shelf_areas_stats <- table(west_ind_shelf_areas[,.(change_above_2fold)])

Eastern Indian

east_ind_spdf_mask

north_extent <- c(xmin(east_ind_spdf_mask_1s), xmax(east_ind_spdf_mask_1s), 0, ymax(east_ind_spdf_mask_1s))
south_extent <- c(xmin(east_ind_spdf_mask_1s), xmax(east_ind_spdf_mask_1s), ymin(east_ind_spdf_mask_1s), 0)

#crop east_ind raster above and below 0
east_ind_spdf_shift_agg_north <- crop(east_ind_spdf_mask_1s, extent(north_extent))

east_ind_spdf_shift_agg_south <- crop(east_ind_spdf_mask_1s, extent(south_extent))

#unfortunately, I think I may have to just do this manually (ugly, I know)

#all chunks for east indian
east_ind_north_latitudes <- seq(0, ymax(east_ind_spdf_mask_1s), by = 1)
east_ind_south_latitudes <- seq(0, ymin(east_ind_spdf_mask_1s), by = -1)

#setup data table to populate in loop, subtracting one to allow for bins
east_ind_shelf_areas <- as.data.table(matrix(nrow = (length(east_ind_north_latitudes)-1+length(east_ind_south_latitudes)-1)))
                                      
east_ind_shelf_areas[, latitude_start := as.numeric(V1)][, latitude_end := as.numeric(V1)][, area_rasterarea := as.numeric(V1)][, area_equalareaproj := as.numeric(V1)][, area_rgeos_gArea := as.numeric(V1)][, V1 := NULL]

#loop for north
for (i in 1:(length(east_ind_north_latitudes)-1)) {
  #setting up extent for slicing by min and max longitudes, and i to i+1 latitudes
  north_extent <- c(xmin(east_ind_spdf_mask_1s), xmax(east_ind_spdf_mask_1s), east_ind_north_latitudes[i], east_ind_north_latitudes[i+1])
  
  #crop raster segement based on bin extent
  segment_north <- crop(east_ind_spdf_mask_1s, extent(north_extent))
  
  #populate data table with latitudinal bin
  east_ind_shelf_areas[i, "latitude_start"] <- east_ind_north_latitudes[i]
  east_ind_shelf_areas[i, "latitude_end"] <- east_ind_north_latitudes[i+1]
  
  if(all(is.na(values(segment_north)))) { #if there's no shelf area within a bin, all area = 0
    
  east_ind_shelf_areas[i, "area_equalareaproj"] <- 0
  east_ind_shelf_areas[i, "area_rasterarea"] <- 0
  east_ind_shelf_areas[i, "area_rgeos_gArea"] <- 0

  
  print(i)
    
  } else { #if there is shelf area within the bin, calculate area of slice
  
    #raster area calculation
      #get sizes of all cells in raster [km2]
    cell_size_raster<-area(segment_north, na.rm=TRUE, weights=FALSE)
    
    #delete NAs from vector of all raster cells
    cell_size_raster<-cell_size_raster[!is.na(segment_north)]
    
    #compute area of all cells in geo_raster
    #full area          <- total # grid cells     * median cell area (using median cares less about extreme values)
    segment_area_raster <- length(cell_size_raster)*median(cell_size_raster) #in km^2
    
  #populate data table with raster area
  east_ind_shelf_areas[i, "area_rasterarea"] <- segment_area_raster
    
  #convert to spatial polygons to check area calculations
    
  #convert segment from raster to polygon, each cell from the raster is an independent polygon, (dissolve means all cells with a value of 1 are a single polygon if connected)
  segment_north.sp <- rasterToPolygons(segment_north, dissolve = T)
  
  #  If x is a SpatialPolygons* object: area of each spatial object in squared meters if the CRS is longitude/latitude, or in squared map units (typically meter)
  
    #project to equal earth area projection
  segment_north.sp.EA <- spTransform(segment_north.sp, CRSobj = equalareaprojection)

  #calculate area of the spatial object in m^2
    polygon_size.sp <- area(segment_north.sp.EA)

    #convert from m^2 to km^2
    segment_area_equalarea <- polygon_size.sp/1e6

    #populate data table with polygon area using raster calculation
  east_ind_shelf_areas[i, "area_equalareaproj"] <- segment_area_equalarea
  
  #and then plain and simple also using rgeos::gArea
  
  area_rgeos_gArea <- gArea(segment_north.sp.EA)/1e6
  
  #populate data table with polygon area using regeos calculation
  east_ind_shelf_areas[i, "area_rgeos_gArea"] <-   area_rgeos_gArea
  
  print(i)
  } 
}
[1] 1
[1] 2
[1] 3
[1] 4
[1] 5
[1] 6
[1] 7
[1] 8
[1] 9
[1] 10
[1] 11
[1] 12
[1] 13
[1] 14
[1] 15
[1] 16
[1] 17
[1] 18
[1] 19
[1] 20
[1] 21
[1] 22
[1] 23
#loop for south
for (i in 1:(length(east_ind_south_latitudes)-1)) {
  south_extent <- c(xmin(east_ind_spdf_mask_1s), xmax(east_ind_spdf_mask_1s), east_ind_south_latitudes[i+1], east_ind_south_latitudes[i]) #order= xmin, xmax, ymin, ymax)
  
  #raster segment
  segment_south <- crop(east_ind_spdf_mask_1s, extent(south_extent))
  
  #add latitude bin info to data table
    east_ind_shelf_areas[i+(length(east_ind_north_latitudes)-1), "latitude_start"] <- east_ind_south_latitudes[i]
  east_ind_shelf_areas[i+(length(east_ind_north_latitudes)-1), "latitude_end"] <- east_ind_south_latitudes[i+1]
  
  
  if(all(is.na(values(segment_south)))) { #if there's no shelf area within a bin, meaning there's no shelf area at that latitude

  east_ind_shelf_areas[i+(length(east_ind_north_latitudes)-1), "area_equalareaproj"] <- 0
  east_ind_shelf_areas[i+(length(east_ind_north_latitudes)-1), "area_rasterarea"] <- 0
    east_ind_shelf_areas[i+(length(east_ind_north_latitudes)-1), "area_rgeos_gArea"] <- 0
  
  print(i)
    
  } else {
  
    #raster area calculation
      #get sizes of all cells in raster [km2]
    cell_size_raster<-area(segment_south, na.rm=TRUE, weights=FALSE)
    
    #delete NAs from vector of all raster cells
    cell_size_raster<-cell_size_raster[!is.na(segment_south)]
    #compute area of all cells in geo_raster
    #full area          <- total # grid cells     * median cell area (using median cares less about extreme values)
    segment_area_raster <- length(cell_size_raster)*median(cell_size_raster)
    
  #populate data table with raster area
  east_ind_shelf_areas[i+(length(east_ind_north_latitudes)-1), "area_rasterarea"] <- segment_area_raster
    
  
  #convert to spatial polygons to check area calculations
    
  #convert segment from raster to polygon, each cell from the raster is an independent polygon, (dissolve means all cells with a value of 1 are a single polygon if connected)
  segment_south.sp <- rasterToPolygons(segment_south, dissolve = T)
  
  #  If x is a SpatialPolygons* object: area of each spatial object in squared meters if the CRS is longitude/latitude, or in squared map units (typically meter)
  
    #project to equal earth area projection
  segment_south.sp.EA <- spTransform(segment_south.sp, CRSobj = equalareaprojection)

  #calculate area of the spatial object in m^2
    polygon_size.sp <- area(segment_south.sp.EA)

    #convert from m^2 to km^2
    segment_area_equalarea <- polygon_size.sp/1e6

    #populate data table with area of polygon from raster::area function
  east_ind_shelf_areas[i+(length(east_ind_north_latitudes)-1), "area_equalareaproj"] <- segment_area_equalarea
  
  #and then plain and simple also using rgeos::gArea
  
  area_rgeos_gArea <- gArea(segment_south.sp.EA)/1e6
  
  #populate data table from rgeos area calculation for projected polygon
  east_ind_shelf_areas[i+(length(east_ind_north_latitudes)-1), "area_rgeos_gArea"] <-   area_rgeos_gArea
  
  print(i)
  } 
}
[1] 1
[1] 2
[1] 3
[1] 4
[1] 5
[1] 6
[1] 7
[1] 8
[1] 9
[1] 10
[1] 11
[1] 12
[1] 13
[1] 14
[1] 15
[1] 16
[1] 17
[1] 18
[1] 19
[1] 20
[1] 21
[1] 22
[1] 23
[1] 24
[1] 25
[1] 26
[1] 27
[1] 28
[1] 29
[1] 30
[1] 31
[1] 32
[1] 33
[1] 34
[1] 35
[1] 36
[1] 37
no non-missing arguments to min; returning Infno non-missing arguments to max; returning -Inf
[1] 38
#compare raster:area calculation, to equal area still using raster::area function, to rgeos::gArea function for polygons

ggplot(data = east_ind_shelf_areas) +
  geom_point(aes(x = latitude_start, y = area_rgeos_gArea), color = "purple", size = 0.5) +
  geom_point(aes(x = latitude_start, y = area_rasterarea), color = "darkgreen", size = 0.5) +
  geom_point(aes(x = latitude_start, y = area_equalareaproj), color = "red", size = 0.5) +
  labs(x = "Latitude", y = "Area km^2") +
  theme_classic()


cor(east_ind_shelf_areas[,3:5], use = "complete.obs")
                   area_rasterarea area_equalareaproj area_rgeos_gArea
area_rasterarea          1.0000000          0.9999989        0.9999989
area_equalareaproj       0.9999989          1.0000000        1.0000000
area_rgeos_gArea         0.9999989          1.0000000        1.0000000
east_ind_shelf_areas[, percent_change := (area_equalareaproj-shift(area_equalareaproj, type = "lag"))/shift(area_equalareaproj, type = "lag")][,area_1000s := area_equalareaproj/1000]

east_ind_shelf_areas[, change_above_2fold := ifelse((percent_change>=1 & percent_change<Inf), 1, ifelse(percent_change<=-0.5, -1, 0))]

east_ind_shelf_areas_highlight <- east_ind_shelf_areas[change_above_2fold != 0,]

east_ind_shelf_areas_stats <- table(east_ind_shelf_areas[,.(change_above_2fold)])

Plots of latitude versus habitat availability

(area_latitude_east_ind  <- ggplot() +
  geom_point(data = east_ind_shelf_areas, aes(x=latitude_start, y=area_1000s), shape =18) +
  geom_line(data = east_ind_shelf_areas, aes(x=latitude_start, y=area_1000s)) +
  geom_rug(data = east_ind_shelf_areas_highlight, aes(x = latitude_start, color = as.factor(change_above_2fold))) +
 labs(x = "Latitude", y = expression(paste("Area (1000s of ", km^{2},")"))) +
  scale_color_discrete(name = "Instances of 2 Fold\n Habitat Change", labels = c("Contraction", "Expansion")) +
  ##annotate("text", x =22, y = 70000, label = "Eastern Indian Ocean") +
  geom_vline(xintercept = 0) +
  xlim(min(east_ind_shelf_areas$latitude_end), max(east_ind_shelf_areas$latitude_end)) +
  coord_flip() +
  theme_classic() +
  theme(plot.margin = margin(10, 40, 10, 10)))


  ggsave(area_latitude_east_ind, filename = "area_latitude_east_ind.jpg", height = 4, units = c("in"))
Saving 7.29 x 4 in image
area_latitude_west_ind  <- ggplot() +
  geom_point(data = west_ind_shelf_areas, aes(x=latitude_start, y=area_1000s), shape =18) + 
  geom_line(data = west_ind_shelf_areas, aes(x=latitude_start, y=area_1000s)) +
    geom_rug(data = east_ind_shelf_areas_highlight, aes(x = latitude_start, color = as.factor(change_above_2fold))) +
 labs(x = "Latitude", y = expression(paste("Area (1000s of ", km^{2},")"))) +
  scale_color_discrete(name = "Instances of 2 Fold\n Habitat Change", labels = c("Contraction", "Expansion")) +
  #annotate("text", x = 30, y = 33000, label = "Western Indian Ocean") +
  geom_vline(xintercept = 0) +
  xlim(min(west_ind_shelf_areas$latitude_end), max(west_ind_shelf_areas$latitude_end)) +
  coord_flip() +
  theme_classic() +
  theme(plot.margin = margin(10, 40, 10, 10))

  ggsave(area_latitude_west_ind, filename = "area_latitude_west_ind.jpg", height = 4, units = c("in"))
Saving 7.29 x 4 in image
area_latitude_west_atl  <- ggplot() +
  geom_point(data = west_atl_shelf_areas, aes(x=latitude_start, y=area_1000s), shape =18) + 
  geom_line(data = west_atl_shelf_areas, aes(x=latitude_start, y=area_1000s)) +
  geom_rug(data = west_atl_shelf_areas_highlight, aes(x = latitude_start, color = as.factor(change_above_2fold))) +
 labs(x = "Latitude", y = expression(paste("Area (1000s of ", km^{2},")"))) +
  scale_color_discrete(name = "Instances of 2 Fold\n Habitat Change", labels = c("Contraction", "Expansion")) +
  #annotate("text", x = 80, y = 120000, label = "Western Atlantic Ocean") +
  geom_vline(xintercept = 0) +
  xlim(min(west_atl_shelf_areas$latitude_end), max(west_atl_shelf_areas$latitude_end)) +
  coord_flip() +
  theme_classic() +
  theme(plot.margin = margin(10, 40, 10, 10))

  ggsave(area_latitude_west_atl, filename = "area_latitude_west_atl.jpg", height = 4, units = c("in"))
Saving 7.29 x 4 in image
area_latitude_east_atl  <- ggplot() +
  geom_point(data = east_atl_shelf_areas, aes(x=latitude_start, y=area_1000s), shape =18) + 
  geom_line(data = east_atl_shelf_areas, aes(x=latitude_start, y=area_1000s)) +
  geom_rug(data = east_atl_shelf_areas_highlight, aes(x = latitude_start, color = as.factor(change_above_2fold))) +
 labs(x = "Latitude", y = expression(paste("Area (1000s of ", km^{2},")"))) +
  scale_color_discrete(name = "Instances of 2 Fold\n Habitat Change", labels = c("Contraction", "Expansion")) +
  #annotate("text", x = 82.5, y = 110000, label = "Eastern Atlantic Ocean") +
  geom_vline(xintercept = 0) +
  xlim(min(east_atl_shelf_areas$latitude_end), max(east_atl_shelf_areas$latitude_end)) +
  coord_flip() +
  theme_classic() +
  theme(plot.margin = margin(10, 40, 10, 10))

  ggsave(area_latitude_east_atl, filename = "area_latitude_east_atl.jpg", height = 4, units = c("in"))
Saving 7.29 x 4 in image
area_latitude_east_pac  <- ggplot() +
  geom_point(data = east_pac_shelf_areas, aes(x=latitude_start, y=area_1000s), shape =18) + 
  geom_line(data = east_pac_shelf_areas, aes(x=latitude_start, y=area_1000s)) +
  geom_rug(data = east_pac_shelf_areas_highlight, aes(x = latitude_start, color = as.factor(change_above_2fold))) +
 labs(x = "Latitude", y = expression(paste("Area (1000s of ", km^{2},")"))) +
  scale_color_discrete(name = "Instances of 2 Fold\n Habitat Change", labels = c("Contraction", "Expansion")) +
  #annotate("text", x = 80, y = 130000, label = "Eastern Pacific Ocean") +
  geom_vline(xintercept = 0) +
  xlim(min(east_pac_shelf_areas$latitude_end), max(east_pac_shelf_areas$latitude_end)) +
  coord_flip() +
  theme_classic() +
  theme(plot.margin = margin(10, 40, 10, 10))

  ggsave(area_latitude_east_pac, filename = "area_latitude_east_pac.jpg", height = 4, units = c("in"))
Saving 7.29 x 4 in image

(area_latitude_west_pac <- ggplot() +
  geom_point(data = west_pac_shelf_areas, aes(x=latitude_start, y=area_1000s), shape =18) + 
  geom_line(data = west_pac_shelf_areas, aes(x=latitude_start, y=area_1000s)) +
  #geom_point(data = west_pac_shelf_areas_highlight, aes(x = latitude_start, y = area), shape =19, color = "seagreen4", size = 2) + 
  geom_rug(data = west_pac_shelf_areas_highlight, aes(x = latitude_start, color = as.factor(change_above_2fold))) +
 labs(x = "Latitude", y = expression(paste("Area (1000s of ", km^{2},")"))) +
  scale_color_discrete(name = "Instances of 2 Fold\n Habitat Change", labels = c("Contraction", "Expansion")) +
  #annotate("text", x = 90, y = 130000, label = "Western Pacific Ocean") +
  geom_vline(xintercept = 0) +
  xlim(min(west_pac_shelf_areas$latitude_end), max(west_pac_shelf_areas$latitude_end)) +
  coord_flip() +
  theme_classic() +
  theme(plot.margin = margin(10, 40, 10, 10)))

  

  ggsave(area_latitude_west_pac, filename = "area_latitude_west_pac.jpg", height = 4, units = c("in"))
Saving 7.29 x 4 in image

How many experience ‘significant’ changes in habitat (at least -50% or +200% change from one bin to another) I will go with IUCN 50% loss -> vulnerable species designation.

Bin shifts –> contractions (loss of 50%) versus expansions (gain of 200%) versus neutral

#call all objects in environment with "stats" string
stats_string<-grep("_stats",names(.GlobalEnv),value=TRUE)
stats_string_list<-do.call("list",mget(stats_string))
names(stats_string_list) <- c("Eastern Indian Ocean" ,"Western Pacific Ocean" ,"Eastern Pacific Ocean" ,"Western Atlantic Ocean" ,"Western Indian Ocean" ,"Eastern Atlantic Ocean")

significant_changes <- as.data.table(rbind(stats_string_list[[1]],stats_string_list[[2]],stats_string_list[[3]],stats_string_list[[4]],stats_string_list[[5]],stats_string_list[[6]]))

colnames(significant_changes) <- c("contraction", "neutral", "expansion")

significant_changes[, region := names(stats_string_list)][,total_bins := contraction + neutral + expansion][,contraction_percent := contraction/total_bins][,neutral_percent := neutral/total_bins][,expansion_percent := expansion/total_bins]

#melt to plot
significant_changes.long <- melt(significant_changes, id.vars = c("region"), variable.name = "change_type", measure.vars = c("contraction_percent", "neutral_percent", "expansion_percent"))

blank_theme <- theme_minimal()+
  theme(
  axis.title.x = element_blank(),
  axis.title.y = element_blank(),
  panel.border = element_blank(),
  panel.grid=element_blank(),
  axis.ticks = element_blank(),
  plot.title=element_text(size=14, face="bold")
  )

ggplot(data = significant_changes.long, aes(x="", y = value, fill = change_type)) +
  geom_bar(stat = "identity", width = 1) +
  coord_polar("y", start=0) +
  scale_fill_manual(values = c("darksalmon", "azure2", "cyan3"), name = "Habitat Change", labels = c(">= 2 Fold Contraction", "< 2 Fold Change", ">= 2 Fold Expansion")) +
  facet_wrap(~region) +
  geom_text(aes(label = paste0(round(value*100,1),"%")), position = position_stack(vjust = 0.1), size = 2) +
  scale_x_discrete(expand = c(0,0)) +
  blank_theme +
  theme(axis.text.x=element_blank())

ggsave(filename = "habitatloss_gain_2fold.pdf")
Saving 7.29 x 4.51 in image

Now, I should make maps for each of these regions

Used https://gist.github.com/valentinitnelav/c7598fcfc8e53658f66feea9d3bafb40 for instructions

library(ggspatial)

  world <- ne_countries(scale = "medium", returnclass = "sf")

# ~~~~~~~~~~~ Download shapefile from www.naturalearthdata.com ~~~~~~~~~~~ #
# Download countries data
download.file(url = "http://www.naturalearthdata.com/http//www.naturalearthdata.com/download/110m/cultural/ne_110m_admin_0_countries.zip", 
              destfile = "ne_110m_admin_0_countries.zip")
trying URL 'http://www.naturalearthdata.com/http//www.naturalearthdata.com/download/110m/cultural/ne_110m_admin_0_countries.zip'
Content type 'application/zip' length 196764 bytes (192 KB)
==================================================
downloaded 192 KB
# unzip the shapefile in the directory mentioned with "exdir" argument
unzip(zipfile="ne_110m_admin_0_countries.zip", exdir = "ne_110m_admin_0_countries")
# delete the zip file
file.remove("ne_110m_admin_0_countries.zip")
[1] TRUE
# read the shapefile with readOGR from rgdal package
NE_countries <- readOGR(dsn = "ne_110m_admin_0_countries", layer = "ne_110m_admin_0_countries")
OGR data source with driver: ESRI Shapefile 
Source: "/Users/zoekitchel/Documents/grad school/Rutgers/Repositories/shelf_habitat_distribution/ne_110m_admin_0_countries", layer: "ne_110m_admin_0_countries"
with 177 features
It has 94 fields
Integer64 fields read as strings:  POP_EST NE_ID 
class(NE_countries) # is a SpatialPolygonsDataFrame object
[1] "SpatialPolygonsDataFrame"
attr(,"package")
[1] "sp"
# ~~~~~~~~~~~ Split world map by "split line" ~~~~~~~~~~~ #

# shift central/prime meridian towards west – positive values only
shift <- 180 +30

# create "split line" to split country polygons
WGS84 <- CRS("+proj=longlat +datum=WGS84 +no_defs +ellps=WGS84 +towgs84=0,0,0")
split.line <- SpatialLines(list(Lines(list(Line(cbind(180-shift,c(-90,90)))), ID="line")), 
                          proj4string=WGS84)

# NOTE - in case of TopologyException' errors when intersecting line with country polygons,
# apply the gBuffer solution suggested at:
# http://gis.stackexchange.com/questions/163445/r-solution-for-topologyexception-input-geom-1-is-invalid-self-intersection-er
NE_countries <- gBuffer(NE_countries, byid=TRUE, width=0)
Spatial object is not projected; GEOS expects planar coordinates
# intersecting line with country polygons
line.gInt <- gIntersection(split.line, NE_countries)
spgeom1 and spgeom2 have different proj4 strings
# create a very thin polygon (buffer) out of the intersecting "split line"
bf <- gBuffer(line.gInt, byid=TRUE, width=0.000001)  
Spatial object is not projected; GEOS expects planar coordinates
# split country polygons using intersecting thin polygon (buffer)
NE_countries.split <- gDifference(NE_countries, bf, byid=TRUE)
spgeom1 and spgeom2 have different proj4 strings
# plot(NE_countries.split) # check map
class(NE_countries.split) # is a SpatialPolygons object
[1] "SpatialPolygons"
attr(,"package")
[1] "sp"
# ~~~~~~~~~~~ Create graticules ~~~~~~~~~~~ #
# create a bounding box - world extent
b.box <- as(raster::extent(-180, 180, -90, 90), "SpatialPolygons")
# assign CRS to box
proj4string(b.box) <- WGS84
# create graticules/grid lines from box
grid <- gridlines(b.box, 
                  easts  = seq(from=-180, to=180, by=20),
                  norths = seq(from=-90, to=90, by=10))

# create labels for graticules
grid.lbl <- labels(grid, side = 1:4)

# transform labels from SpatialPointsDataFrame to a data table that ggplot can use
grid.lbl.DT <- data.table(grid.lbl@coords, grid.lbl@data)

# prepare labels with regular expression:
# - delete unwanted labels
grid.lbl.DT[, labels := gsub(pattern="180\\*degree|90\\*degree\\*N|90\\*degree\\*S", replacement="", x=labels)]
# - replace pattern "*degree" with "°" (* needs to be escaped with \\)
grid.lbl.DT[, lbl := gsub(pattern="\\*degree", replacement="°", x=labels)]
# - delete any remaining "*"
grid.lbl.DT[, lbl := gsub(pattern="*\\*", replacement="", x=lbl)]

# adjust coordinates of labels so that they fit inside the globe
grid.lbl.DT[, long := ifelse(coords.x1 %in% c(-180,180), coords.x1*175/180, coords.x1)]
grid.lbl.DT[, lat  := ifelse(coords.x2 %in% c(-90,90), coords.x2*82/90, coords.x2)]

# ~~~~~~~~~~~ Prepare data for ggplot, shift & project coordinates ~~~~~~~~~~~ #
# give the PORJ.4 string for Eckert IV projection ( changed to different projection, "+proj=eck4 +lon_0=0 +x_0=0 +y_0=0 +ellps=WGS84 +datum=WGS84 +units=m +no_defs" for eckert)
PROJ <- "+proj=longlat +datum=WGS84 +no_defs +ellps=WGS84 +towgs84=0,0,0" 

# transform graticules from SpatialLines to a data table that ggplot can use
grid.DT <- data.table(map_data(SpatialLinesDataFrame(sl=grid, 
                                                     data=data.frame(1:length(grid)), 
                                                     match.ID = FALSE)))
database does not (uniquely) contain the field 'name'.
# project coordinates
# assign matrix of projected coordinates as two columns in data table
grid.DT[, c("X","Y") := data.table(project(cbind(long, lat), proj=PROJ))]

# project coordinates of labels
grid.lbl.DT[, c("X","Y") := data.table(project(cbind(long, lat), proj=PROJ))]

# transform split country polygons in a data table that ggplot can use
Country.DT_shift <- data.table(map_data(as(NE_countries.split, "SpatialPolygonsDataFrame")))
database does not (uniquely) contain the field 'name'.
Country.DT <- data.table(map_data(as(NE_countries, "SpatialPolygonsDataFrame")))
# Shift coordinates
Country.DT_shift[, long.new := long + shift]
Country.DT_shift[, long.new := ifelse(long.new > 180, long.new-360, long.new)]

# project coordinates 
Country.DT[, c("X","Y") := data.table(project(cbind(long, lat), proj=PROJ))]
Country.DT_shift[, c("X","Y") := data.table(project(cbind(long.new, lat), proj=PROJ))]

# ~~~~~~~~~~~ Plot map ~~~~~~~~~~~ #
ggplot() + 
    # add projected countries
    geom_polygon(data = Country.DT_shift, 
                 aes(x = long.new+150, y = lat, group = group), 
                 colour = "gray70", 
                 fill = "gray90", 
                 size = 0.25) +
    # add graticules
    geom_path(data = grid.DT, 
              aes(x = X, y = Y, group = group), 
              linetype = "dotted", colour = "grey50", size = .25) +
    # add a bounding box (select graticules at edges)
    geom_path(data = grid.DT[(long %in% c(-180,180) & region == "NS")
                             |(long %in% c(-180,180) & lat %in% c(-90,90) & region == "EW")], 
              aes(x = X, y = Y, group = group), 
              linetype = "solid", colour = "black", size = .3) +
    # add graticule labels
    geom_text(data = grid.lbl.DT, # latitude
              aes(x = X, y = Y, label = lbl), 
              colour = "grey50", size = 2) +
    # ensures that one unit on the x-axis is the same length as one unit on the y-axis
    coord_equal() + # same as coord_fixed(ratio = 1)
    # set empty theme
    theme_void()


region_maps <- list()
regions_shift_projection <- c("west_pac_spdf_shift", "east_pac_spdf_shift")



for (i in 1:length(region_names)) {
  
  region_spdf <- get(paste0(region_names[i], "_mask"))
  
  if(region_names[i] %in% regions_shift_projection) {
  
  #pacific centered projection
  
  region_spdf_mask_1s_extent <- extent(get(paste0(region_names[i],"_mask_1s"))) # take extent of region
  
  #convert rasters to dfs data frame
  region_spdf <- as(get(paste0(region_names[i],"_mask_1s")), "SpatialPixelsDataFrame")
  region_df <- as.data.frame(region_spdf)
  colnames(region_df) <- c("value", "x", "y")
  
  
  (region_maps[[i]] <- ggplot() + 
    # add projected countries
    geom_polygon(data = Country.DT_shift, 
                 aes(x = long.new+150, y = lat, group = group), 
                 colour = "gray70", 
                 fill = "gray90", 
                 size = 0.25) +
    geom_tile(data = region_df, aes(x = x, y = y, fill = value), color = "seagreen4") +
    coord_sf(x = c(region_spdf_mask_1s_extent[1], region_spdf_mask_1s_extent[2]), y = c(region_spdf_mask_1s_extent[3], region_spdf_mask_1s_extent[4])) +
    labs( x = expression("Longitude ("*~degree*E*")"), y = expression("Latitude ("*~degree*N*")")) +
    geom_abline(intercept = 0, slope = 0) +
    theme_classic() +
    theme(legend.position = "none"))
  
  filename <- paste0(region_names[i], "_map.jpg")
  ggsave(plot = region_maps[[i]], filename = filename, height = 4, units = c("in"))
  
  } else {

  #atlantic centered projection
  region_spdf_mask_1s_extent <- extent(get(paste0(region_names[i],"_mask_1s"))) # take extent of region
  
  #convert rasters to dfs data frame
  region_spdf <- as(get(paste0(region_names[i],"_mask_1s")), "SpatialPixelsDataFrame")
  region_df <- as.data.frame(region_spdf)
  colnames(region_df) <- c("value", "x", "y")
  
  
  (region_maps[[i]] <- ggplot() + 
    # add projected countries
    geom_polygon(data = Country.DT, 
                 aes(x = long, y = lat, group = group), 
                 colour = "gray70", 
                 fill = "gray90", 
                 size = 0.25) +
    geom_tile(data = region_df, aes(x = x, y = y, fill = value), color = "seagreen4") +
    coord_sf(x = c(region_spdf_mask_1s_extent[1], region_spdf_mask_1s_extent[2]), y = c(region_spdf_mask_1s_extent[3], region_spdf_mask_1s_extent[4])) +
    labs( x = expression("Longitude ("*~degree*E*")"), y = expression("Latitude ("*~degree*N*")")) +
    geom_abline(intercept = 0, slope = 0) +
    theme_classic() +
    theme(legend.position = "none"))
  
  filename <- paste0(region_names[i], "_map.jpg")
  ggsave(plot = region_maps[[i]], filename = filename, height = 4, units = c("in"))
  
  }
  
  }
Saving 7 x 4 in image

Combining plots

region_maps: “west_pac_spdf_shift”, “east_pac_spdf_shift”, “west_atl_spdf”, “west_ind_spdf”, “east_atl_spdf_nobuf”, “east_ind_spdf”

Plots of area versus latitude area_latitude_east_pac

Now, combine plots

library(egg)
library(ggpubr)

#west pacific
(west_pacific_merge_map_plot <- egg::ggarrange(region_maps[[1]], 
          area_latitude_west_pac 
          + 
               theme(axis.text.y = element_blank(),
                     axis.ticks.y = element_blank(),
                     axis.title.y = element_blank() ), 

          nrow = 1,
          top = T))
range backtransformation not implemented in this coord; results may be wrong.

ggsave(plot = west_pacific_merge_map_plot, filename = "west_pacific_merge_map_plot.jpg", width = 7, height = 3, units = "in")

#east pacific
(east_pacific_merge_map_plot <- egg::ggarrange(region_maps[[2]], 
          area_latitude_east_pac 
          + 
               theme(axis.text.y = element_blank(),
                     axis.ticks.y = element_blank(),
                     axis.title.y = element_blank() )
          , 

          nrow = 1,
          top = T))
range backtransformation not implemented in this coord; results may be wrong.

ggsave(plot = east_pacific_merge_map_plot, filename = "east_pacific_merge_map_plot.jpg", width = 7, height = 3, units = "in")


#west atlantic
(west_atlantic_merge_map_plot <- egg::ggarrange(region_maps[[3]], 
          area_latitude_west_atl
          + 
               theme(axis.text.y = element_blank(),
                     axis.ticks.y = element_blank(),
                     axis.title.y = element_blank() )
          , 

          nrow = 1,
          top = T))
range backtransformation not implemented in this coord; results may be wrong.

ggsave(plot = west_atlantic_merge_map_plot, filename = "west_atlantic_merge_map_plot.jpg", width = 7, height = 3, units = "in")

#west indian
(west_indian_merge_map_plot <- egg::ggarrange(region_maps[[4]], 
          area_latitude_west_ind 
          + 
               theme(axis.text.y = element_blank(),
                     axis.ticks.y = element_blank(),
                     axis.title.y = element_blank() )
          , 

          nrow = 1,
          top = T))
range backtransformation not implemented in this coord; results may be wrong.

ggsave(plot = west_indian_merge_map_plot, filename = "west_indian_merge_map_plot.jpg", width = 7, height = 3, units = "in")

#east atlantic
(east_atlantic_merge_map_plot <- egg::ggarrange(region_maps[[5]], 
          area_latitude_east_atl
          + 
               theme(axis.text.y = element_blank(),
                     axis.ticks.y = element_blank(),
                     axis.title.y = element_blank() )
          , 

          nrow = 1,
          top = T))
range backtransformation not implemented in this coord; results may be wrong.

ggsave(plot = east_atlantic_merge_map_plot, filename = "east_atlantic_merge_map_plot.jpg", width = 7, height = 3, units = "in")

#east indian
(east_indian_merge_map_plot <- egg::ggarrange(region_maps[[6]], 
          area_latitude_east_ind
          + 
               theme(axis.text.y = element_blank(),
                     axis.ticks.y = element_blank(),
                     axis.title.y = element_blank() )
          , 

          nrow = 1,
          top = T))
range backtransformation not implemented in this coord; results may be wrong.

ggsave(plot = east_indian_merge_map_plot, filename = "east_indian_merge_map_plot.jpg", width = 7, height = 3, units = "in")

Make map of world

Each region coded with # expansions and # contractions


save(significant_changes.long, significant_changes, file = "significant_changes.RData")
LS0tCnRpdGxlOiAiRGVncmVlIHNoaWZ0cyBidXQgcHJvamVjdGVkIHRvIGNhbGN1bGF0ZSBBcmVhIgpvdXRwdXQ6IGh0bWxfbm90ZWJvb2sKLS0tCgpUaGlzIHNjcmlwdCBpcyB2ZXJ5IHNpbWlsYXIgdG8gZGVncmVlX3NoaWZ0cy4gSG93ZXZlciwgSSBhbSBjYWxjdWxhdGluZyBhcmVhIGZyb20gcG9seWdvbnMgaW5zdGVhZCBvZiByYXN0ZXI6OmFyZWEgb2YgcmFzdGVycyB0byBzZWUgaG93IGFjY3VyYXRlIHRoZSBjYWxjdWxhdGlvbnMgYXJlLiAKCgpEZWdyZWUgc2hpZnRzCgpTZWNvbmQgcGFydCBvZiBwYXBlciwgaWYgd2UgbW92ZSBhd2F5IGZyb20gZXF1YXRvciBieSAxy5ogZGVncmVlLCBob3cgbXVjaCBoYWJpdGF0IGRvIHdlIGdhaW4gb3IgbG9zdAoKSSBuZWVkIHRvIGxvb2sgYXQgc2hlbGYgYXJlYSBieSBkZWdyZWVzIGxhdGl0dWRlCgpgYGB7ciBzZXR1cH0KbGlicmFyeShyYXN0ZXIpCmxpYnJhcnkoc2YpCmxpYnJhcnkobmNkZjQpCmxpYnJhcnkocm1hcHNoYXBlcikKbGlicmFyeSh0aWR5dmVyc2UpCmxpYnJhcnkoZGlwdGVzdCkKbGlicmFyeShtb21lbnRzKQpsaWJyYXJ5KHZpcmlkaXMpICNjb2xvcnMKbGlicmFyeShkYXRhLnRhYmxlKQpsaWJyYXJ5KGh5ZHJvVFNNKSAjaHlwc29tZXRyaWMgY3VydmVzCmxpYnJhcnkoZ3JpZEV4dHJhKQpsaWJyYXJ5KG1hcHRvb2xzKQpsaWJyYXJ5KHJnZGFsKQpsaWJyYXJ5KHJnZW9zKQpsaWJyYXJ5KFNwYURFUykKbGlicmFyeShybmF0dXJhbGVhcnRoKQpsaWJyYXJ5KHJuYXR1cmFsZWFydGhkYXRhKQoKCmV0b3BvX3NoZWxmX2RmIDwtIHJlYWRSRFMoIn4vRG9jdW1lbnRzL2dyYWQgc2Nob29sL1J1dGdlcnMvUmVwb3NpdG9yaWVzL3NoZWxmX2hhYml0YXRfZGlzdHJpYnV0aW9uL2V0b3BvX3NoZWxmX2RmLnJkcyIpCiNicmluZyBpbiBiYXRoeW1ldHJ5IGRhdGEgZnJhbWUgZm9yIHNoZWxmIHJlZ2lvbnMKCiNMTUVzCkxNRV9zcGRmIDwtIHJlYWRPR1IoIkxNRTY2L0xNRXM2Ni5zaHAiKSAjc3BhdGlhbCBwb2ludHMgZGF0YSBmcmFtZSB3aXRoIGFsbCA2NiBMTUVzCgoKI2NvbnZlcnQgdG8gZXF1YWwgYXJlYSBwcm9qZWN0aW9uCiNlcXVhbGFyZWFwcm9qZWN0aW9uPC0gY3JzKCIgK3Byb2o9ZXFlYXJ0aCAiKQoKI1RoZSBMYW1iZXJ0IGF6aW11dGhhbCBlcXVhbC1hcmVhIHByb2plY3Rpb24gaXMgYSBwYXJ0aWN1bGFyIG1hcHBpbmcgZnJvbSBhIHNwaGVyZSB0byBhIGRpc2suIEl0IGFjY3VyYXRlbHkgcmVwcmVzZW50cyBhcmVhIGluIGFsbCByZWdpb25zIG9mIHRoZSBzcGhlcmUsIGJ1dCBpdCBkb2VzIG5vdCBhY2N1cmF0ZWx5IHJlcHJlc2VudCBhbmdsZXMuCmVxdWFsYXJlYXByb2plY3Rpb248LSBjcnMoIiArcHJvaj1sYWVhICIpCgoKCgpgYGAKCk1ha2UgYmF0aHltZXRyeSBkYXRhIGZyYW1lIGludG8gcmFzdGVyICh0aGlzIHRha2VzIGEgYml0KQoKTm90ZSB0aGF0IEkgYW0gdHJ5aW5nIHRvIHVzZSB0aGUgW2VxdWFsIGFyZWEgcHJvamVjdGlvbl0oaHR0cHM6Ly93d3cuci1ibG9nZ2Vycy5jb20vMjAxOC8wOS9xdWljay1oaXQtdXNpbmctdGhlLW5ldy1lcXVhbC1lYXJ0aC1wcm9qZWN0aW9uLWluLXIvKQpgYGB7ciBiYXRoeSB0byByYXN0ZXJ9CgpldG9wb19zaGVsZl9yYXN0ZXIgPC0gcmFzdGVyRnJvbVhZWihldG9wb19zaGVsZl9kZiwgY3JzID0gY3JzKExNRV9zcGRmKSkKCiNyZWNsYXNzaWZ5IGFsbCB2YWx1ZXMgPDIwMDBtIGluIGRlcHRoIHRvIDEgaW5zdGVhZCBvZiBhY3R1YWwgZGVwdGgKZXRvcG9fc2hlbGZfcmFzdGVyPC0gcmVjbGFzc2lmeShldG9wb19zaGVsZl9yYXN0ZXIsY2JpbmQoLUluZiwgSW5mLCAxKSkKCmBgYAoKClNob3VsZCBnbyBieSBwcm9qZWN0aW9ucyBvZiB3aGVyZSBzcGVjaWVzIGFyZSBtb3Zpbmc6CiJNYXJpbmUgc3BlY2llcyAofjgwJSBiZWluZyBlY3RvdGhlcm1zIGluIHRoZSBkYXRhYmFzZTsgRXh0ZW5kZWQgRGF0YSBGaWcuIDIpIGhhdmUgbW92ZWQgdG93YXJkcyB0aGUgcG9sZXMgYXQgYSBtZWFuICjCsXMuZS5tLikgcGFjZSBvZiA1LjkyIMKxIDAuOTQga20geXLiiJIxIChvbmUtc2FtcGxlIFN0dWRlbnTigJlzIHQtdGVzdDogdD02LjI2OyBkLmYuIHJlc2lkdWFscz0yMzsgUD0yLjIww5cxMOKAkzYpLCB3aGljaCBpcyBhbG1vc3Qgc2l4IHRpbWVzIGZhc3RlciB0aGFuIHRlcnJlc3RyaWFsIHNwZWNpZXMgKG9uZS13YXkgYW5hbHlzaXMgb2YgdmFyaWFuY2UgKEFOT1ZBKTogRj0xMi42ODsgZC5mLiBmYWN0b3I9MTsgZC5mLiByZXNpZHVhbHM9NDU7IFA9OC44OMOXMTDigJM0KS4iIExlbm9pciAyMDIwCgo1LjkyIGttICogMTAgPSA1OS4yIGttIGluIDEwIHllYXJzCgo1OS4yIGttIGlzIGhvdyBtYW55IGRlZ3JlZXM/CgoxwrAgPSAxMTEga20KCnNvLCAKCmBgYHtyIHF1aWNrIGNvbnZlcnNpb259CjU5LjIvMTExKjEKCmBgYAoKMC41MzMzy5ogaXMgcmVwcmVzZW50YXRpdmUgb2YgZGVjYWRhbCBzaGlmdHMsIGJ1dCwgZm9yIGJldHRlciB2aXN1YWxpemF0aW9uIGxldCdzIGdvIHdpdGggMcuaIChyZXByZXNlbnRhdGl2ZSBvZiAyMCB5ZWFyIHNoaWZ0cykKCkkgd2lsbCBwdXQgYXJlYXMgaW50byAxy5ogQmlucyAoMTgwIHRvdGFsIGRlZ3JlZXMsIHNvIDE4MC8xPTE4MCB0b3RhbCBsYXRpdHVkaW5hbCBiaW5zKQoKYGBge3J9CjE4MC8xCmBgYAoKSG93IGRvZXMgY29udGluZW50YWwgc2hlbGYgaGFiaXRhdCBjaGFuZ2Ugd2l0aCBsYXRpdHVkZT8KCkxvb2sgYXQgY29udGlndW91cyBjb2FzdCBsaW5lcy4KCkkgYW0gZ29pbmcgdG8gbGVhdmUgb3V0IEFudGFyY3RpY2EgKDYxKSBhbmQgdGhlIEFyY3RpYyAoNjQpIGFzIEFudGFyY3RpY2EgZHJvd25lZCBvdXQgcGF0dGVybnMgaW4gbG93ZXIgbGF0aXR1ZGVzIGFuZCBBcmN0aWMgZG9lc24ndCBoYXZlIG11Y2ggaGFiaXRhdCBzaGFsbG93ZXIgdGhhbiAyMDAwbSB0byBiZWdpbiB3aXRoLiAKCkVhc3Rlcm4gQXRsYW50aWMgKDMpCi0xOSwgMjAsIDIxLCAyMiwgMjMsIDI0LCAyNSwgMjYsIDI3LCAyOCwgMjksIDU4LCA1OSwgNjAsIDYyCgpXZXN0ZXJuIEF0bGFudGljICgyKQotIDUsIDYsIDcsIDgsIDksIDEyLCAxNCwgMTUsIDE2LCAxNywgMTgsIDYzLCA2NgoKRWFzdGVybiBQYWNpZmljICgxKQotIDEsIDIsIDMsIDQsIDExLCAxMywgNTQsIDU1LCA2NQoKV2VzdGVybiBJbmRpYW4gKDQpCi0zMCwgMzEsIDMyLCAzMwoKRWFzdGVybiBJbmRpYW4gKDUpCi0zNCwgMzgsIDQzLCA0NCwgNDUKCldlc3Rlcm4gUGFjaWZpYyAoNikKMSwJMzUsCTM2LAkzNywJMzksCTQwLAk0MSwJNDIsCTQ2LAk0NywJNDgsCTQ5LAk1MCwJNTEsCTUyLAk1MywJNTQsCTU2LAk1NywJNjUKCk1lcmdlIExNRXMgaW50byA2IGNvYXN0bGluZSByZWdpb25zCgotIGtlZXAgaW4gbWluZCwgTE1FIDEgKDEmNikgYW5kIDU0ICgxJjYpIGFuZCA2NSAoMSY2KSBhcHBlYXIgaW4gbXVsdGlwbGUKYGBge3IgbWVyZ2luZyBMTUVzfQp3ZXN0X3BhYyA8LSBjKDEsCTM1LAkzNiwJMzcsCTM5LAk0MCwJNDEsCTQyLAk0NiwJNDcsCTQ4LAk0OSwJNTAsCTUxLAk1MiwJNTMsCTU0LAk1NiwJNTcsCTY1KQplYXN0X3BhYyA8LSBjKDEsIDIsIDMsIDQsIDExLCAxMywgNTQsIDU1LCA2NSkKd2VzdF9hdGwgPC0gYyg1LCA2LCA3LCA4LCA5LCAxMiwgMTQsIDE1LCAxNiwgMTcsIDE4LCA2MywgNjYpCmVhc3RfYXRsIDwtIGMoMTksIDIwLCAyMSwgMjIsIDIzLCAyNCwgMjUsIDI2LCAyNywgMjgsIDI5LCA1OCwgNTksIDYwLCA2MikKd2VzdF9pbmQgPC0gYygzMCwgMzEsIDMyLCAzMykKZWFzdF9pbmQgPC0gYygzNCwgMzgsIDQzLCA0NCwgNDUpCgojc3VicmVnaW9ucyBiYXNlZCBvbiBMTUVfbnVtYmVyCndlc3RfcGFjX3NwZGYgPC0gTE1FX3NwZGZbKExNRV9zcGRmJExNRV9OVU1CRVIpICVpbiUgd2VzdF9wYWMsXQplYXN0X3BhY19zcGRmIDwtIExNRV9zcGRmWyhMTUVfc3BkZiRMTUVfTlVNQkVSKSAlaW4lIGVhc3RfcGFjLF0Kd2VzdF9hdGxfc3BkZiA8LSBMTUVfc3BkZlsoTE1FX3NwZGYkTE1FX05VTUJFUikgJWluJSB3ZXN0X2F0bCxdCndlc3RfaW5kX3NwZGYgPC0gTE1FX3NwZGZbKExNRV9zcGRmJExNRV9OVU1CRVIpICVpbiUgd2VzdF9pbmQsXQplYXN0X2F0bF9zcGRmIDwtIExNRV9zcGRmWyhMTUVfc3BkZiRMTUVfTlVNQkVSKSAlaW4lIGVhc3RfYXRsLF0KZWFzdF9pbmRfc3BkZiA8LSBMTUVfc3BkZlsoTE1FX3NwZGYkTE1FX05VTUJFUikgJWluJSBlYXN0X2luZCxdCgojZm9yIHN1YnJlZ2lvbnMgdGhhdCBzcGFuIDM2MCwgd2UgbmVlZCB0byBjaGFuZ2UgQ1JTIGEgYml0Cm5ld0NSU193ZXN0IDwtICIrcHJvaj1sb25nbGF0ICtkYXR1bT1XR1M4NCArbG9uX3dyYXA9MTgwIiAjdGhpcyBzaGlmdHMgMTgwIGRlZ3JlZXMKd2VzdF9wYWNfc3BkZl9zaGlmdCA8LSBzcFRyYW5zZm9ybSh3ZXN0X3BhY19zcGRmLCBDUlMobmV3Q1JTX3dlc3QpKQp3ZXN0X3BhY19zcGRmX3NoaWZ0IDwtIGdCdWZmZXIod2VzdF9wYWNfc3BkZl9zaGlmdCwgYnlpZD1UUlVFLCB3aWR0aD0wKSAjZ2V0cyByaWQgb2YgYnVmZmVycywgYWxsb3dzIGZvciB1bmlvbgoKbmV3Q1JTX2Vhc3QgPC0gIitwcm9qPWxvbmdsYXQgK2RhdHVtPVdHUzg0ICtsb25fd3JhcD0xODAiICN0aGlzIHNoaWZ0cyAxODAgZGVncmVlcwplYXN0X3BhY19zcGRmX3NoaWZ0IDwtIHNwVHJhbnNmb3JtKGVhc3RfcGFjX3NwZGYsIENSUyhuZXdDUlNfZWFzdCkpCmVhc3RfcGFjX3NwZGZfc2hpZnQgPC0gZ0J1ZmZlcihlYXN0X3BhY19zcGRmX3NoaWZ0LCBieWlkPVRSVUUsIHdpZHRoPTApICNnZXRzIHJpZCBvZiBidWZmZXJzLCBhbGxvd3MgZm9yIHVuaW9uCgojcm90YXRlIHJhc3RlciBmb3IgYmF0aHltZXRyeSAoZ3VpZGVkIGJ5IGV4dGVudCBvZiBldG9wb3NoZWxmIHJhc3RlciwgIHRoYXQncyB3aHkgd2Fja3kgI3MpCngxIDwtIGNyb3AoZXRvcG9fc2hlbGZfcmFzdGVyLCBleHRlbnQoLTE4MC4wMTY3LCAtMC4wMTY3LCAtOTAuMDE2NjcsIDkwLjAxNjY3KSkKeDIgPC0gY3JvcChldG9wb19zaGVsZl9yYXN0ZXIsIGV4dGVudCgwLCAxODAuMDE2NywgLTkwLjAxNjY3LCA5MC4wMTY2NykpICAgCmV4dGVudCh4MSkgPC0gYygxODAuMDE2NywgMzYwLjAxNjcsIC05MC4wMTY2NyAsIDkwLjAxNjY3KQpldG9wb19zaGVsZl9yYXN0ZXJfMTgwIDwtIG1lcmdlKHgxLCB4MikKCiNnZXQgcmlkIG9mIGJ1ZmZlciBmb3IgZWFzdCBhdGwgYXMgd2VsbCB0byBhbGxvdyBmb3IgdW5pb24KCmVhc3RfYXRsX3NwZGZfbm9idWYgPC0gZ0J1ZmZlcihlYXN0X2F0bF9zcGRmLCBieWlkPVRSVUUsIHdpZHRoPTApCgpyZWdpb25fbmFtZXMgPC0gYygid2VzdF9wYWNfc3BkZl9zaGlmdCIsICJlYXN0X3BhY19zcGRmX3NoaWZ0IiwgIndlc3RfYXRsX3NwZGYiLCAid2VzdF9pbmRfc3BkZiIsICJlYXN0X2F0bF9zcGRmX25vYnVmIiwgImVhc3RfaW5kX3NwZGYiKQoKCgojZGlzc29sdmUgYWxsIHBvbHlnb25zIGJ5IHJlZ2lvbgpmb3IgKGkgaW4gMTpsZW5ndGgocmVnaW9uX25hbWVzKSkgewogIG5hbWUgPC0gcGFzdGUwKHJlZ2lvbl9uYW1lc1tpXSwgIl9hZ2ciKQogIGFzc2lnbihuYW1lLCBnVW5hcnlVbmlvbihnZXQocmVnaW9uX25hbWVzW2ldKSkpICNkaXNzb2x2ZSBwb2x5Z29ucyB3aXRoaW4gY29hc3RsaW5lIHJlZ2lvbiBpbnRvIG9uZQp9CgpgYGAKCgpFeHRyYWN0IGJhdGh5bWV0cnkgZGF0YSBmcm9tIHBvbHlnb24gb25seSB0byBtYWtlIHN1cmUgd2UncmUgbGltaXRpbmcgdG8gc2hlbGYgcmVnaW9ucyBhYm92ZSAyMDAwIG1ldGVycwoKYGBge3IgcG9seWdvbiB0byByYXN0ZXJ9CgpyZWdpb25fbmFtZXNfc2hpZnQgPC0gcmVnaW9uX25hbWVzWzE6Ml0KCgpyZWdpb25fbmFtZXNfbm9zaGlmdCA8LSByZWdpb25fbmFtZXNbMzo2XQoKCmZvciAoaSBpbiAxOmxlbmd0aChyZWdpb25fbmFtZXNfbm9zaGlmdCkpIHsKI2Nyb3AgYmF0aHltZXRyeSBsYXllciB0byBMTUUgc3Vic2V0IChjb250aW5lbnRhbCBzaGVsZiBoYWJpdGF0IGluIExNRXMpCiAgcmFzdGVyX2V4dGVudCA8LQogICAgICAgY3JvcChldG9wb19zaGVsZl9yYXN0ZXIsIGV4dGVudChnZXQocGFzdGUwKHJlZ2lvbl9uYW1lc19ub3NoaWZ0W2ldLCAiX2FnZyIpKSkpCgojd2hpY2ggYXJlYXMgb2YgcmFzdGVyIGZhbGwgd2l0aGluIGJvcmRlcnM/CiAgYXNzaWduKHBhc3RlMChyZWdpb25fbmFtZXNfbm9zaGlmdFtpXSwgIl9tYXNrIiksCiAgICAgICBtYXNrKHJhc3Rlcl9leHRlbnQsIGdldChwYXN0ZTAocmVnaW9uX25hbWVzX25vc2hpZnRbaV0sICJfYWdnIikpKSkKICAKICAgIGFzc2lnbihwYXN0ZTAocmVnaW9uX25hbWVzX25vc2hpZnRbaV0sICJfbWFza18xcyIpLAogICAgICAgcmVjbGFzc2lmeShnZXQocGFzdGUwKHJlZ2lvbl9uYW1lc19ub3NoaWZ0W2ldLCAiX21hc2siKSksIGNiaW5kKC1JbmYsIEluZiwgMSkpKQoKICAKCn0KCiNlZGl0IGZvciBlYXN0X3BhY19zcGRmX3NoaWZ0IGFuZCB3ZXN0X3BhY19zcGRmX3NoaWZ0ICgrMTgwy5opCgpmb3IgKGkgaW4gMTpsZW5ndGgocmVnaW9uX25hbWVzX3NoaWZ0WzE6Ml0pKSB7CiNjcm9wIGJhdGh5IGxheWVyIHRvIExNRSBzdWJzZXQKICByYXN0ZXJfZXh0ZW50IDwtCiAgICAgICBjcm9wKGV0b3BvX3NoZWxmX3Jhc3Rlcl8xODAsIGV4dGVudChnZXQocGFzdGUwKHJlZ2lvbl9uYW1lc19zaGlmdFtpXSwgIl9hZ2ciKSkpKQoKI3doaWNoIGFyZWFzIG9mIHJhc3RlciBmYWxsIHdpdGhpbiBib3JkZXJzPwogIGFzc2lnbihwYXN0ZTAocmVnaW9uX25hbWVzX3NoaWZ0W2ldLCAiX21hc2siKSwKICAgICAgIG1hc2socmFzdGVyX2V4dGVudCwgZ2V0KHBhc3RlMChyZWdpb25fbmFtZXNfc2hpZnRbaV0sICJfYWdnIikpKSkKICAKICAgIGFzc2lnbihwYXN0ZTAocmVnaW9uX25hbWVzX3NoaWZ0W2ldLCAiX21hc2tfMXMiKSwKICAgICAgIHJlY2xhc3NpZnkoZ2V0KHBhc3RlMChyZWdpb25fbmFtZXNfc2hpZnRbaV0sICJfbWFzayIpKSwgY2JpbmQoLUluZiwgSW5mLCAxKSkpCgp9CgpgYGAKCgpIb3cgdG8gY2FsY3VsYXRlIGFyZWE/CgotIHJhc3Rlcjo6YXJlYSgpClJhc3RlciBvYmplY3RzOiBDb21wdXRlIHRoZSBhcHByb3hpbWF0ZSBzdXJmYWNlIGFyZWEgb2YgY2VsbHMgaW4gYW4gdW5wcm9qZWN0ZWQgKGxvbmdpdHVkZS9sYXRpdHVkZSkgUmFzdGVyIG9iamVjdC4gSXQgaXMgYW4gYXBwcm94aW1hdGlvbiBiZWNhdXNlIGFyZWEgaXMgY29tcHV0ZWQgYXMgdGhlIGhlaWdodCAobGF0aXR1ZGluYWwgc3Bhbikgb2YgYSBjZWxsICh3aGljaCBpcyBjb25zdGFudCBhbW9uZyBhbGwgY2VsbHMpIHRpbWVzIHRoZSB3aWR0aCAobG9uZ2l0dWRpbmFsIHNwYW4pIGluIHRoZSAobGF0aXR1ZGluYWwpIG1pZGRsZSBvZiBhIGNlbGwuIFRoZSB3aWR0aCBpcyBzbWFsbGVyIGF0IHRoZSBwb2xld2FyZCBzaWRlIHRoYW4gYXQgdGhlIGVxdWF0b3Itd2FyZCBzaWRlIG9mIGEgY2VsbC4gVGhpcyB2YXJpYXRpb24gaXMgZ3JlYXRlc3QgbmVhciB0aGUgcG9sZXMgYW5kIHRoZSB2YWx1ZXMgYXJlIHRodXMgbm90IHZlcnkgcHJlY2lzZSBmb3IgdmVyeSBoaWdoIGxhdGl0dWRlcy4gSWYgeCBpcyBhIFJhc3Rlciogb2JqZWN0OiBSYXN0ZXJMYXllciBvciBSYXN0ZXJCcmljay4gQ2VsbCB2YWx1ZXMgcmVwcmVzZW50IHRoZSBzaXplIG9mIHRoZSBjZWxsIGluIGttMiwgb3IgdGhlIHJlbGF0aXZlIHNpemUgaWYgd2VpZ2h0cz1UUlVFCgoKCi0gcmFzdGVyOjphcmVhKCkgClNwYXRpYWxQb2x5Z29uczogQ29tcHV0ZSB0aGUgYXJlYSBvZiB0aGUgc3BhdGlhbCBmZWF0dXJlcy4gV29ya3MgZm9yIGJvdGggcGxhbmFyIGFuZCBhbmd1bGFyIChsb24vbGF0KSBjb29yZGluYXRlIHJlZmVyZW5jZSBzeXN0ZW1zLiBJZiB4IGlzIGEgU3BhdGlhbFBvbHlnb25zKiBvYmplY3Q6IGFyZWEgb2YgZWFjaCBzcGF0aWFsIG9iamVjdCBpbiBzcXVhcmVkIG1ldGVycyBpZiB0aGUgQ1JTIGlzIGxvbmdpdHVkZS9sYXRpdHVkZSwgb3IgaW4gc3F1YXJlZCBtYXAgdW5pdHMgKHR5cGljYWxseSBtZXRlcikKCi0gcmdlb3M6OmdBcmVhClJldHVybnMgdGhlIGFyZWEgb2YgdGhlIGdlb21ldHJ5IGluIHRoZSB1bml0cyBvZiB0aGUgY3VycmVudCBwcm9qZWN0aW9uLiBCeSBkZWZpbml0aW9uIG5vbi1bTVVMVEldUE9MWUdPTiBnZW9tZXRyaWVzIGhhdmUgYW4gYXJlYSBvZiAwLiBUaGUgYXJlYSBvZiBhIFBPTFlHT04gaXMgdGhlIGFyZWEgb2YgaXRzIHNoZWxsIGxlc3MgdGhlIGFyZWEgb2YgYW55IGhvbGVzLiBOb3RlIHRoYXQgdGhpcyB2YWx1ZSBtYXkgYmUgZGlmZmVyZW50IGZyb20gdGhlIGFyZWEgc2xvdCBvZiB0aGUgUG9seWdvbnMgY2xhc3MgYXMgdGhpcyB2YWx1ZSBkb2VzIG5vdCBzdWJ0cmFjdCB0aGUgYXJlYSBvZiBhbnkgaG9sZXMgaW4gdGhlIGdlb21ldHJ5LgoKCk5vdywgd2Ugd2lsbCBzcGxpdCBlYWNoIGNvYXN0bGluZSByYXN0ZXIgaW50byBsYXRpdHVkaW5hbCBiaW5zIG9mIDHLmgoKV2VzdGVybiBQYWNpZmljCmBgYHtyIHNwbGl0IHJhc3RlciBmb3Igd2VzdGVybiBwYWNpZmljfQpub3J0aF9leHRlbnQgPC0gYyh4bWluKHdlc3RfcGFjX3NwZGZfc2hpZnRfbWFza18xcyksIHhtYXgod2VzdF9wYWNfc3BkZl9zaGlmdF9tYXNrXzFzKSwgMCwgeW1heCh3ZXN0X3BhY19zcGRmX3NoaWZ0X21hc2tfMXMpKQpzb3V0aF9leHRlbnQgPC0gYyh4bWluKHdlc3RfcGFjX3NwZGZfc2hpZnRfbWFza18xcyksIHhtYXgod2VzdF9wYWNfc3BkZl9zaGlmdF9tYXNrXzFzKSwgeW1pbih3ZXN0X3BhY19zcGRmX3NoaWZ0X21hc2tfMXMpLCAwKQoKI2Nyb3Agd2VzdF9wYWMgcmFzdGVyIGFib3ZlIGFuZCBiZWxvdyAwCndlc3RfcGFjX3NwZGZfc2hpZnRfYWdnX25vcnRoIDwtIGNyb3Aod2VzdF9wYWNfc3BkZl9zaGlmdF9tYXNrXzFzLCBleHRlbnQobm9ydGhfZXh0ZW50KSkKCndlc3RfcGFjX3NwZGZfc2hpZnRfYWdnX3NvdXRoIDwtIGNyb3Aod2VzdF9wYWNfc3BkZl9zaGlmdF9tYXNrXzFzLCBleHRlbnQoc291dGhfZXh0ZW50KSkKCiN1bmZvcnR1bmF0ZWx5LCBJIHRoaW5rIEkgbWF5IGhhdmUgdG8ganVzdCBkbyB0aGlzIG1hbnVhbGx5ICh1Z2x5LCBJIGtub3cpCgojYWxsIGNodW5rcyBmb3Igd2VzdCBwYWNpZmljCndlc3RfcGFjX25vcnRoX2xhdGl0dWRlcyA8LSBzZXEoMCwgeW1heCh3ZXN0X3BhY19zcGRmX3NoaWZ0X21hc2tfMXMpLCBieSA9IDEpCndlc3RfcGFjX3NvdXRoX2xhdGl0dWRlcyA8LSBzZXEoMCwgeW1pbih3ZXN0X3BhY19zcGRmX3NoaWZ0X21hc2tfMXMpLCBieSA9IC0xKQoKI3NldHVwIGRhdGEgdGFibGUgdG8gcG9wdWxhdGUgaW4gbG9vcCwgc3VidHJhY3Rpbmcgb25lIHRvIGFsbG93IGZvciBiaW5zCndlc3RfcGFjX3NoZWxmX2FyZWFzIDwtIGFzLmRhdGEudGFibGUobWF0cml4KG5yb3cgPSAobGVuZ3RoKHdlc3RfcGFjX25vcnRoX2xhdGl0dWRlcyktMStsZW5ndGgod2VzdF9wYWNfc291dGhfbGF0aXR1ZGVzKS0xKSkpCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCndlc3RfcGFjX3NoZWxmX2FyZWFzWywgbGF0aXR1ZGVfc3RhcnQgOj0gYXMubnVtZXJpYyhWMSldWywgbGF0aXR1ZGVfZW5kIDo9IGFzLm51bWVyaWMoVjEpXVssIGFyZWFfcmFzdGVyYXJlYSA6PSBhcy5udW1lcmljKFYxKV1bLCBhcmVhX2VxdWFsYXJlYXByb2ogOj0gYXMubnVtZXJpYyhWMSldWywgYXJlYV9yZ2Vvc19nQXJlYSA6PSBhcy5udW1lcmljKFYxKV1bLCBWMSA6PSBOVUxMXQoKI2xvb3AgZm9yIG5vcnRoCmZvciAoaSBpbiAxOihsZW5ndGgod2VzdF9wYWNfbm9ydGhfbGF0aXR1ZGVzKS0xKSkgewogICNzZXR0aW5nIHVwIGV4dGVudCBmb3Igc2xpY2luZyBieSBtaW4gYW5kIG1heCBsb25naXR1ZGVzLCBhbmQgaSB0byBpKzEgbGF0aXR1ZGVzCiAgbm9ydGhfZXh0ZW50IDwtIGMoeG1pbih3ZXN0X3BhY19zcGRmX3NoaWZ0X21hc2tfMXMpLCB4bWF4KHdlc3RfcGFjX3NwZGZfc2hpZnRfbWFza18xcyksIHdlc3RfcGFjX25vcnRoX2xhdGl0dWRlc1tpXSwgd2VzdF9wYWNfbm9ydGhfbGF0aXR1ZGVzW2krMV0pCiAgCiAgI2Nyb3AgcmFzdGVyIHNlZ2VtZW50IGJhc2VkIG9uIGJpbiBleHRlbnQKICBzZWdtZW50X25vcnRoIDwtIGNyb3Aod2VzdF9wYWNfc3BkZl9zaGlmdF9tYXNrXzFzLCBleHRlbnQobm9ydGhfZXh0ZW50KSkKICAKICAjcG9wdWxhdGUgZGF0YSB0YWJsZSB3aXRoIGxhdGl0dWRpbmFsIGJpbgogIHdlc3RfcGFjX3NoZWxmX2FyZWFzW2ksICJsYXRpdHVkZV9zdGFydCJdIDwtIHdlc3RfcGFjX25vcnRoX2xhdGl0dWRlc1tpXQogIHdlc3RfcGFjX3NoZWxmX2FyZWFzW2ksICJsYXRpdHVkZV9lbmQiXSA8LSB3ZXN0X3BhY19ub3J0aF9sYXRpdHVkZXNbaSsxXQogIAogIGlmKGFsbChpcy5uYSh2YWx1ZXMoc2VnbWVudF9ub3J0aCkpKSkgeyAjaWYgdGhlcmUncyBubyBzaGVsZiBhcmVhIHdpdGhpbiBhIGJpbiwgYWxsIGFyZWEgPSAwCiAgICAKICB3ZXN0X3BhY19zaGVsZl9hcmVhc1tpLCAiYXJlYV9lcXVhbGFyZWFwcm9qIl0gPC0gMAogIHdlc3RfcGFjX3NoZWxmX2FyZWFzW2ksICJhcmVhX3Jhc3RlcmFyZWEiXSA8LSAwCiAgd2VzdF9wYWNfc2hlbGZfYXJlYXNbaSwgImFyZWFfcmdlb3NfZ0FyZWEiXSA8LSAwCgogIAogIHByaW50KGkpCiAgICAKICB9IGVsc2UgeyAjaWYgdGhlcmUgaXMgc2hlbGYgYXJlYSB3aXRoaW4gdGhlIGJpbiwgY2FsY3VsYXRlIGFyZWEgb2Ygc2xpY2UKICAKICAgICNyYXN0ZXIgYXJlYSBjYWxjdWxhdGlvbgogICAgICAjZ2V0IHNpemVzIG9mIGFsbCBjZWxscyBpbiByYXN0ZXIgW2ttMl0KICAgIGNlbGxfc2l6ZV9yYXN0ZXI8LWFyZWEoc2VnbWVudF9ub3J0aCwgbmEucm09VFJVRSwgd2VpZ2h0cz1GQUxTRSkKICAgIAogICAgI2RlbGV0ZSBOQXMgZnJvbSB2ZWN0b3Igb2YgYWxsIHJhc3RlciBjZWxscwogICAgY2VsbF9zaXplX3Jhc3RlcjwtY2VsbF9zaXplX3Jhc3RlclshaXMubmEoc2VnbWVudF9ub3J0aCldCiAgICAKICAgICNjb21wdXRlIGFyZWEgb2YgYWxsIGNlbGxzIGluIGdlb19yYXN0ZXIKICAgICNmdWxsIGFyZWEgICAgICAgICAgPC0gdG90YWwgIyBncmlkIGNlbGxzICAgICAqIG1lZGlhbiBjZWxsIGFyZWEgKHVzaW5nIG1lZGlhbiBjYXJlcyBsZXNzIGFib3V0IGV4dHJlbWUgdmFsdWVzKQogICAgc2VnbWVudF9hcmVhX3Jhc3RlciA8LSBsZW5ndGgoY2VsbF9zaXplX3Jhc3RlcikqbWVkaWFuKGNlbGxfc2l6ZV9yYXN0ZXIpICNpbiBrbV4yCiAgICAKICAjcG9wdWxhdGUgZGF0YSB0YWJsZSB3aXRoIHJhc3RlciBhcmVhCiAgd2VzdF9wYWNfc2hlbGZfYXJlYXNbaSwgImFyZWFfcmFzdGVyYXJlYSJdIDwtIHNlZ21lbnRfYXJlYV9yYXN0ZXIKICAgIAogICNjb252ZXJ0IHRvIHNwYXRpYWwgcG9seWdvbnMgdG8gY2hlY2sgYXJlYSBjYWxjdWxhdGlvbnMKICAgIAogICNjb252ZXJ0IHNlZ21lbnQgZnJvbSByYXN0ZXIgdG8gcG9seWdvbiwgZWFjaCBjZWxsIGZyb20gdGhlIHJhc3RlciBpcyBhbiBpbmRlcGVuZGVudCBwb2x5Z29uLCAoZGlzc29sdmUgbWVhbnMgYWxsIGNlbGxzIHdpdGggYSB2YWx1ZSBvZiAxIGFyZSBhIHNpbmdsZSBwb2x5Z29uIGlmIGNvbm5lY3RlZCkKICBzZWdtZW50X25vcnRoLnNwIDwtIHJhc3RlclRvUG9seWdvbnMoc2VnbWVudF9ub3J0aCwgZGlzc29sdmUgPSBUKQogIAogICMgIElmIHggaXMgYSBTcGF0aWFsUG9seWdvbnMqIG9iamVjdDogYXJlYSBvZiBlYWNoIHNwYXRpYWwgb2JqZWN0IGluIHNxdWFyZWQgbWV0ZXJzIGlmIHRoZSBDUlMgaXMgbG9uZ2l0dWRlL2xhdGl0dWRlLCBvciBpbiBzcXVhcmVkIG1hcCB1bml0cyAodHlwaWNhbGx5IG1ldGVyKQogIAogICAgI3Byb2plY3QgdG8gZXF1YWwgZWFydGggYXJlYSBwcm9qZWN0aW9uCiAgc2VnbWVudF9ub3J0aC5zcC5FQSA8LSBzcFRyYW5zZm9ybShzZWdtZW50X25vcnRoLnNwLCBDUlNvYmogPSBlcXVhbGFyZWFwcm9qZWN0aW9uKQoKICAjY2FsY3VsYXRlIGFyZWEgb2YgdGhlIHNwYXRpYWwgb2JqZWN0IGluIG1eMgogICAgcG9seWdvbl9zaXplLnNwIDwtIGFyZWEoc2VnbWVudF9ub3J0aC5zcC5FQSkKCiAgICAjY29udmVydCBmcm9tIG1eMiB0byBrbV4yCiAgICBzZWdtZW50X2FyZWFfZXF1YWxhcmVhIDwtIHBvbHlnb25fc2l6ZS5zcC8xZTYKCiAgICAjcG9wdWxhdGUgZGF0YSB0YWJsZSB3aXRoIHBvbHlnb24gYXJlYSB1c2luZyByYXN0ZXIgY2FsY3VsYXRpb24KICB3ZXN0X3BhY19zaGVsZl9hcmVhc1tpLCAiYXJlYV9lcXVhbGFyZWFwcm9qIl0gPC0gc2VnbWVudF9hcmVhX2VxdWFsYXJlYQogIAogICNhbmQgdGhlbiBwbGFpbiBhbmQgc2ltcGxlIGFsc28gdXNpbmcgcmdlb3M6OmdBcmVhCiAgCiAgYXJlYV9yZ2Vvc19nQXJlYSA8LSBnQXJlYShzZWdtZW50X25vcnRoLnNwLkVBKS8xZTYKICAKICAjcG9wdWxhdGUgZGF0YSB0YWJsZSB3aXRoIHBvbHlnb24gYXJlYSB1c2luZyByZWdlb3MgY2FsY3VsYXRpb24KICB3ZXN0X3BhY19zaGVsZl9hcmVhc1tpLCAiYXJlYV9yZ2Vvc19nQXJlYSJdIDwtICAgYXJlYV9yZ2Vvc19nQXJlYQogIAogIHByaW50KGkpCiAgfSAKfQoKI2xvb3AgZm9yIHNvdXRoCmZvciAoaSBpbiAxOihsZW5ndGgod2VzdF9wYWNfc291dGhfbGF0aXR1ZGVzKS0xKSkgewogIHNvdXRoX2V4dGVudCA8LSBjKHhtaW4od2VzdF9wYWNfc3BkZl9zaGlmdF9tYXNrXzFzKSwgeG1heCh3ZXN0X3BhY19zcGRmX3NoaWZ0X21hc2tfMXMpLCB3ZXN0X3BhY19zb3V0aF9sYXRpdHVkZXNbaSsxXSwgd2VzdF9wYWNfc291dGhfbGF0aXR1ZGVzW2ldKSAjb3JkZXI9IHhtaW4sIHhtYXgsIHltaW4sIHltYXgpCiAgCiAgI3Jhc3RlciBzZWdtZW50CiAgc2VnbWVudF9zb3V0aCA8LSBjcm9wKHdlc3RfcGFjX3NwZGZfc2hpZnRfbWFza18xcywgZXh0ZW50KHNvdXRoX2V4dGVudCkpCiAgCiAgI2FkZCBsYXRpdHVkZSBiaW4gaW5mbyB0byBkYXRhIHRhYmxlCiAgICB3ZXN0X3BhY19zaGVsZl9hcmVhc1tpKyhsZW5ndGgod2VzdF9wYWNfbm9ydGhfbGF0aXR1ZGVzKS0xKSwgImxhdGl0dWRlX3N0YXJ0Il0gPC0gd2VzdF9wYWNfc291dGhfbGF0aXR1ZGVzW2ldCiAgd2VzdF9wYWNfc2hlbGZfYXJlYXNbaSsobGVuZ3RoKHdlc3RfcGFjX25vcnRoX2xhdGl0dWRlcyktMSksICJsYXRpdHVkZV9lbmQiXSA8LSB3ZXN0X3BhY19zb3V0aF9sYXRpdHVkZXNbaSsxXQogIAogIAogIGlmKGFsbChpcy5uYSh2YWx1ZXMoc2VnbWVudF9zb3V0aCkpKSkgeyAjaWYgdGhlcmUncyBubyBzaGVsZiBhcmVhIHdpdGhpbiBhIGJpbiwgbWVhbmluZyB0aGVyZSdzIG5vIHNoZWxmIGFyZWEgYXQgdGhhdCBsYXRpdHVkZQogICAgCiAgd2VzdF9wYWNfc2hlbGZfYXJlYXNbaSsobGVuZ3RoKHdlc3RfcGFjX25vcnRoX2xhdGl0dWRlcyktMSksICJhcmVhX2VxdWFsYXJlYXByb2oiXSA8LSAwCiAgd2VzdF9wYWNfc2hlbGZfYXJlYXNbaSsobGVuZ3RoKHdlc3RfcGFjX25vcnRoX2xhdGl0dWRlcyktMSksICJhcmVhX3Jhc3RlcmFyZWEiXSA8LSAwCiAgICB3ZXN0X3BhY19zaGVsZl9hcmVhc1tpKyhsZW5ndGgod2VzdF9wYWNfbm9ydGhfbGF0aXR1ZGVzKS0xKSwgImFyZWFfcmdlb3NfZ0FyZWEiXSA8LSAwCiAgCiAgcHJpbnQoaSkKICAgIAogIH0gZWxzZSB7CiAgCiAgICAjcmFzdGVyIGFyZWEgY2FsY3VsYXRpb24KICAgICAgI2dldCBzaXplcyBvZiBhbGwgY2VsbHMgaW4gcmFzdGVyIFtrbTJdCiAgICBjZWxsX3NpemVfcmFzdGVyPC1hcmVhKHNlZ21lbnRfc291dGgsIG5hLnJtPVRSVUUsIHdlaWdodHM9RkFMU0UpCiAgICAKICAgICNkZWxldGUgTkFzIGZyb20gdmVjdG9yIG9mIGFsbCByYXN0ZXIgY2VsbHMKICAgIGNlbGxfc2l6ZV9yYXN0ZXI8LWNlbGxfc2l6ZV9yYXN0ZXJbIWlzLm5hKHNlZ21lbnRfc291dGgpXQogICAgI2NvbXB1dGUgYXJlYSBvZiBhbGwgY2VsbHMgaW4gZ2VvX3Jhc3RlcgogICAgI2Z1bGwgYXJlYSAgICAgICAgICA8LSB0b3RhbCAjIGdyaWQgY2VsbHMgICAgICogbWVkaWFuIGNlbGwgYXJlYSAodXNpbmcgbWVkaWFuIGNhcmVzIGxlc3MgYWJvdXQgZXh0cmVtZSB2YWx1ZXMpCiAgICBzZWdtZW50X2FyZWFfcmFzdGVyIDwtIGxlbmd0aChjZWxsX3NpemVfcmFzdGVyKSptZWRpYW4oY2VsbF9zaXplX3Jhc3RlcikKICAgIAogICNwb3B1bGF0ZSBkYXRhIHRhYmxlIHdpdGggcmFzdGVyIGFyZWEKICB3ZXN0X3BhY19zaGVsZl9hcmVhc1tpKyhsZW5ndGgod2VzdF9wYWNfbm9ydGhfbGF0aXR1ZGVzKS0xKSwgImFyZWFfcmFzdGVyYXJlYSJdIDwtIHNlZ21lbnRfYXJlYV9yYXN0ZXIKICAgIAogIAogICNjb252ZXJ0IHRvIHNwYXRpYWwgcG9seWdvbnMgdG8gY2hlY2sgYXJlYSBjYWxjdWxhdGlvbnMKICAgIAogICNjb252ZXJ0IHNlZ21lbnQgZnJvbSByYXN0ZXIgdG8gcG9seWdvbiwgZWFjaCBjZWxsIGZyb20gdGhlIHJhc3RlciBpcyBhbiBpbmRlcGVuZGVudCBwb2x5Z29uLCAoZGlzc29sdmUgbWVhbnMgYWxsIGNlbGxzIHdpdGggYSB2YWx1ZSBvZiAxIGFyZSBhIHNpbmdsZSBwb2x5Z29uIGlmIGNvbm5lY3RlZCkKICBzZWdtZW50X3NvdXRoLnNwIDwtIHJhc3RlclRvUG9seWdvbnMoc2VnbWVudF9zb3V0aCwgZGlzc29sdmUgPSBUKQogIAogICMgIElmIHggaXMgYSBTcGF0aWFsUG9seWdvbnMqIG9iamVjdDogYXJlYSBvZiBlYWNoIHNwYXRpYWwgb2JqZWN0IGluIHNxdWFyZWQgbWV0ZXJzIGlmIHRoZSBDUlMgaXMgbG9uZ2l0dWRlL2xhdGl0dWRlLCBvciBpbiBzcXVhcmVkIG1hcCB1bml0cyAodHlwaWNhbGx5IG1ldGVyKQogIAogICAgI3Byb2plY3QgdG8gZXF1YWwgZWFydGggYXJlYSBwcm9qZWN0aW9uCiAgc2VnbWVudF9zb3V0aC5zcC5FQSA8LSBzcFRyYW5zZm9ybShzZWdtZW50X3NvdXRoLnNwLCBDUlNvYmogPSBlcXVhbGFyZWFwcm9qZWN0aW9uKQoKICAjY2FsY3VsYXRlIGFyZWEgb2YgdGhlIHNwYXRpYWwgb2JqZWN0IGluIG1eMgogICAgcG9seWdvbl9zaXplLnNwIDwtIGFyZWEoc2VnbWVudF9zb3V0aC5zcC5FQSkKCiAgICAjY29udmVydCBmcm9tIG1eMiB0byBrbV4yCiAgICBzZWdtZW50X2FyZWFfZXF1YWxhcmVhIDwtIHBvbHlnb25fc2l6ZS5zcC8xZTYKCiAgICAjcG9wdWxhdGUgZGF0YSB0YWJsZSB3aXRoIGFyZWEgb2YgcG9seWdvbiBmcm9tIHJhc3Rlcjo6YXJlYSBmdW5jdGlvbgogIHdlc3RfcGFjX3NoZWxmX2FyZWFzW2krKGxlbmd0aCh3ZXN0X3BhY19ub3J0aF9sYXRpdHVkZXMpLTEpLCAiYXJlYV9lcXVhbGFyZWFwcm9qIl0gPC0gc2VnbWVudF9hcmVhX2VxdWFsYXJlYQogIAogICNhbmQgdGhlbiBwbGFpbiBhbmQgc2ltcGxlIGFsc28gdXNpbmcgcmdlb3M6OmdBcmVhCiAgCiAgYXJlYV9yZ2Vvc19nQXJlYSA8LSBnQXJlYShzZWdtZW50X3NvdXRoLnNwLkVBKS8xZTYKICAKICAjcG9wdWxhdGUgZGF0YSB0YWJsZSBmcm9tIHJnZW9zIGFyZWEgY2FsY3VsYXRpb24gZm9yIHByb2plY3RlZCBwb2x5Z29uCiAgd2VzdF9wYWNfc2hlbGZfYXJlYXNbaSsobGVuZ3RoKHdlc3RfcGFjX25vcnRoX2xhdGl0dWRlcyktMSksICJhcmVhX3JnZW9zX2dBcmVhIl0gPC0gICBhcmVhX3JnZW9zX2dBcmVhCiAgCiAgcHJpbnQoaSkKICB9IAp9CgojY29tcGFyZSByYXN0ZXI6YXJlYSBjYWxjdWxhdGlvbiwgdG8gZXF1YWwgYXJlYSBzdGlsbCB1c2luZyByYXN0ZXI6OmFyZWEgZnVuY3Rpb24sIHRvIHJnZW9zOjpnQXJlYSBmdW5jdGlvbiBmb3IgcG9seWdvbnMKCmdncGxvdChkYXRhID0gd2VzdF9wYWNfc2hlbGZfYXJlYXMpICsKICBnZW9tX3BvaW50KGFlcyh4ID0gbGF0aXR1ZGVfc3RhcnQsIHkgPSBhcmVhX3JnZW9zX2dBcmVhKSwgY29sb3IgPSAicHVycGxlIiwgc2l6ZSA9IDAuNSkgKwogIGdlb21fcG9pbnQoYWVzKHggPSBsYXRpdHVkZV9zdGFydCwgeSA9IGFyZWFfcmFzdGVyYXJlYSksIGNvbG9yID0gImRhcmtncmVlbiIsIHNpemUgPSAwLjUpICsKICBnZW9tX3BvaW50KGFlcyh4ID0gbGF0aXR1ZGVfc3RhcnQsIHkgPSBhcmVhX2VxdWFsYXJlYXByb2opLCBjb2xvciA9ICJyZWQiLCBzaXplID0gMC41KSArCiAgbGFicyh4ID0gIkxhdGl0dWRlIiwgeSA9ICJBcmVhIGttXjIiKSArCiAgdGhlbWVfY2xhc3NpYygpCgpjb3Iod2VzdF9wYWNfc2hlbGZfYXJlYXNbLDM6NV0sIHVzZSA9ICJjb21wbGV0ZS5vYnMiKQoKc2F2ZSh3ZXN0X3BhY19zaGVsZl9hcmVhcywgZmlsZSA9ICJ3ZXN0X3BhY19zaGVsZl9hcmVhcy5SRGF0YSIpCgpgYGAKCkNsYXNzaWZ5IGJ5IHBlcmNlbnQgY2hhbmdlISEKCmJldHdlZW4gMSBhbmQgSW5mICUgY2hhbmdlID0gYXQgbGVhc3QgMiBmb2xkIGluY3JlYXNlIChub3RlIEkgY2xhc3NpZmllZCBhbnkgY2hhbmdlIGZyb20gMCB0byBzb21ldGhpbmcgYXMgTk9UIGEgc2lnbmlmaWNhbnQgY2hhbmdlLCBzaG91bGQgcmV0dXJuIHRvIHRoaXMgY29uY2VwdHVhbGx5KQoKYmV0d2VlbiAtMC41IGFuZCAtaW5mICUgY2hhbmdlID0gYXQgbGVhc3QgMiBmb2xkIGRlY3JlYXNlCgpiZXR3ZWVuIC0wLjQ5OSBhbmQgMC45OTkgPSBubyBzaWduaWZpY2FudCBjaGFuZ2UgCgpGb3IgYXJlYSBtZXRyaWMgaGVyZSwgSSB1c2VkIHRoZSByYXN0ZXI6OmFyZWEgZnVuY3Rpb24gYXBwbGllZCB0byB0aGUgcHJvamVjdGVkIHNoYXBlZmlsZQpgYGB7ciBwZXJjZW50IHNoaWZ0IHdlc3Rlcm4gcGFjaWZpY30Kd2VzdF9wYWNfc2hlbGZfYXJlYXNbLCBwZXJjZW50X2NoYW5nZSA6PSAoYXJlYV9lcXVhbGFyZWFwcm9qLXNoaWZ0KGFyZWFfZXF1YWxhcmVhcHJvaiwgdHlwZSA9ICJsYWciKSkvc2hpZnQoYXJlYV9lcXVhbGFyZWFwcm9qLCB0eXBlID0gImxhZyIpXVssYXJlYV8xMDAwcyA6PSBhcmVhX2VxdWFsYXJlYXByb2ovMTAwMF0KCndlc3RfcGFjX3NoZWxmX2FyZWFzWywgY2hhbmdlX2Fib3ZlXzJmb2xkIDo9IGlmZWxzZSgocGVyY2VudF9jaGFuZ2U+PTEgJiBwZXJjZW50X2NoYW5nZTxJbmYpLCAxLCBpZmVsc2UocGVyY2VudF9jaGFuZ2U8PS0wLjUsIC0xLCAwKSldCgp3ZXN0X3BhY19zaGVsZl9hcmVhc19oaWdobGlnaHQgPC0gd2VzdF9wYWNfc2hlbGZfYXJlYXNbY2hhbmdlX2Fib3ZlXzJmb2xkICE9IDAsXQoKd2VzdF9wYWNfc2hlbGZfYXJlYXNfc3RhdHMgPC0gdGFibGUod2VzdF9wYWNfc2hlbGZfYXJlYXNbLC4oY2hhbmdlX2Fib3ZlXzJmb2xkKV0pCmBgYAoKCkVhc3Rlcm4gUGFjaWZpYwoKZWFzdF9wYWNfc3BkZl9zaGlmdAoKYGBge3Igc3BsaXQgcmFzdGVyIGZvciBlYXN0ZXJuIHBhY2lmaWN9Cm5vcnRoX2V4dGVudCA8LSBjKHhtaW4od2VzdF9pbmRfc3BkZl9tYXNrXzFzKSwgeG1heCh3ZXN0X2luZF9zcGRmX21hc2tfMXMpLCAwLCB5bWF4KHdlc3RfaW5kX3NwZGZfbWFza18xcykpCnNvdXRoX2V4dGVudCA8LSBjKHhtaW4od2VzdF9pbmRfc3BkZl9tYXNrXzFzKSwgeG1heCh3ZXN0X2luZF9zcGRmX21hc2tfMXMpLCB5bWluKHdlc3RfaW5kX3NwZGZfbWFza18xcyksIDApCgojY3JvcCBlYXN0X3BhYyByYXN0ZXIgYWJvdmUgYW5kIGJlbG93IDAKZWFzdF9wYWNfc3BkZl9zaGlmdF9hZ2dfbm9ydGggPC0gY3JvcCh3ZXN0X2luZF9zcGRmX21hc2tfMXMsIGV4dGVudChub3J0aF9leHRlbnQpKQoKZWFzdF9wYWNfc3BkZl9zaGlmdF9hZ2dfc291dGggPC0gY3JvcCh3ZXN0X2luZF9zcGRmX21hc2tfMXMsIGV4dGVudChzb3V0aF9leHRlbnQpKQoKI3VuZm9ydHVuYXRlbHksIEkgdGhpbmsgSSBtYXkgaGF2ZSB0byBqdXN0IGRvIHRoaXMgbWFudWFsbHkgKHVnbHksIEkga25vdykKCiNhbGwgY2h1bmtzIGZvciBlYXN0IHBhY2lmaWMKZWFzdF9wYWNfbm9ydGhfbGF0aXR1ZGVzIDwtIHNlcSgwLCB5bWF4KHdlc3RfaW5kX3NwZGZfbWFza18xcyksIGJ5ID0gMSkKZWFzdF9wYWNfc291dGhfbGF0aXR1ZGVzIDwtIHNlcSgwLCB5bWluKHdlc3RfaW5kX3NwZGZfbWFza18xcyksIGJ5ID0gLTEpCgojc2V0dXAgZGF0YSB0YWJsZSB0byBwb3B1bGF0ZSBpbiBsb29wLCBzdWJ0cmFjdGluZyBvbmUgdG8gYWxsb3cgZm9yIGJpbnMKZWFzdF9wYWNfc2hlbGZfYXJlYXMgPC0gYXMuZGF0YS50YWJsZShtYXRyaXgobnJvdyA9IChsZW5ndGgoZWFzdF9wYWNfbm9ydGhfbGF0aXR1ZGVzKS0xK2xlbmd0aChlYXN0X3BhY19zb3V0aF9sYXRpdHVkZXMpLTEpKSkKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKZWFzdF9wYWNfc2hlbGZfYXJlYXNbLCBsYXRpdHVkZV9zdGFydCA6PSBhcy5udW1lcmljKFYxKV1bLCBsYXRpdHVkZV9lbmQgOj0gYXMubnVtZXJpYyhWMSldWywgYXJlYV9yYXN0ZXJhcmVhIDo9IGFzLm51bWVyaWMoVjEpXVssIGFyZWFfZXF1YWxhcmVhcHJvaiA6PSBhcy5udW1lcmljKFYxKV1bLCBhcmVhX3JnZW9zX2dBcmVhIDo9IGFzLm51bWVyaWMoVjEpXVssIFYxIDo9IE5VTExdCgojbG9vcCBmb3Igbm9ydGgKZm9yIChpIGluIDE6KGxlbmd0aChlYXN0X3BhY19ub3J0aF9sYXRpdHVkZXMpLTEpKSB7CiAgI3NldHRpbmcgdXAgZXh0ZW50IGZvciBzbGljaW5nIGJ5IG1pbiBhbmQgbWF4IGxvbmdpdHVkZXMsIGFuZCBpIHRvIGkrMSBsYXRpdHVkZXMKICBub3J0aF9leHRlbnQgPC0gYyh4bWluKHdlc3RfaW5kX3NwZGZfbWFza18xcyksIHhtYXgod2VzdF9pbmRfc3BkZl9tYXNrXzFzKSwgZWFzdF9wYWNfbm9ydGhfbGF0aXR1ZGVzW2ldLCBlYXN0X3BhY19ub3J0aF9sYXRpdHVkZXNbaSsxXSkKICAKICAjY3JvcCByYXN0ZXIgc2VnZW1lbnQgYmFzZWQgb24gYmluIGV4dGVudAogIHNlZ21lbnRfbm9ydGggPC0gY3JvcCh3ZXN0X2luZF9zcGRmX21hc2tfMXMsIGV4dGVudChub3J0aF9leHRlbnQpKQogIAogICNwb3B1bGF0ZSBkYXRhIHRhYmxlIHdpdGggbGF0aXR1ZGluYWwgYmluCiAgZWFzdF9wYWNfc2hlbGZfYXJlYXNbaSwgImxhdGl0dWRlX3N0YXJ0Il0gPC0gZWFzdF9wYWNfbm9ydGhfbGF0aXR1ZGVzW2ldCiAgZWFzdF9wYWNfc2hlbGZfYXJlYXNbaSwgImxhdGl0dWRlX2VuZCJdIDwtIGVhc3RfcGFjX25vcnRoX2xhdGl0dWRlc1tpKzFdCiAgCiAgaWYoYWxsKGlzLm5hKHZhbHVlcyhzZWdtZW50X25vcnRoKSkpKSB7ICNpZiB0aGVyZSdzIG5vIHNoZWxmIGFyZWEgd2l0aGluIGEgYmluLCBhbGwgYXJlYSA9IDAKICAgIAogIGVhc3RfcGFjX3NoZWxmX2FyZWFzW2ksICJhcmVhX2VxdWFsYXJlYXByb2oiXSA8LSAwCiAgZWFzdF9wYWNfc2hlbGZfYXJlYXNbaSwgImFyZWFfcmFzdGVyYXJlYSJdIDwtIDAKICBlYXN0X3BhY19zaGVsZl9hcmVhc1tpLCAiYXJlYV9yZ2Vvc19nQXJlYSJdIDwtIDAKCiAgCiAgcHJpbnQoaSkKICAgIAogIH0gZWxzZSB7ICNpZiB0aGVyZSBpcyBzaGVsZiBhcmVhIHdpdGhpbiB0aGUgYmluLCBjYWxjdWxhdGUgYXJlYSBvZiBzbGljZQogIAogICAgI3Jhc3RlciBhcmVhIGNhbGN1bGF0aW9uCiAgICAgICNnZXQgc2l6ZXMgb2YgYWxsIGNlbGxzIGluIHJhc3RlciBba20yXQogICAgY2VsbF9zaXplX3Jhc3RlcjwtYXJlYShzZWdtZW50X25vcnRoLCBuYS5ybT1UUlVFLCB3ZWlnaHRzPUZBTFNFKQogICAgCiAgICAjZGVsZXRlIE5BcyBmcm9tIHZlY3RvciBvZiBhbGwgcmFzdGVyIGNlbGxzCiAgICBjZWxsX3NpemVfcmFzdGVyPC1jZWxsX3NpemVfcmFzdGVyWyFpcy5uYShzZWdtZW50X25vcnRoKV0KICAgIAogICAgI2NvbXB1dGUgYXJlYSBvZiBhbGwgY2VsbHMgaW4gZ2VvX3Jhc3RlcgogICAgI2Z1bGwgYXJlYSAgICAgICAgICA8LSB0b3RhbCAjIGdyaWQgY2VsbHMgICAgICogbWVkaWFuIGNlbGwgYXJlYSAodXNpbmcgbWVkaWFuIGNhcmVzIGxlc3MgYWJvdXQgZXh0cmVtZSB2YWx1ZXMpCiAgICBzZWdtZW50X2FyZWFfcmFzdGVyIDwtIGxlbmd0aChjZWxsX3NpemVfcmFzdGVyKSptZWRpYW4oY2VsbF9zaXplX3Jhc3RlcikgI2luIGttXjIKICAgIAogICNwb3B1bGF0ZSBkYXRhIHRhYmxlIHdpdGggcmFzdGVyIGFyZWEKICBlYXN0X3BhY19zaGVsZl9hcmVhc1tpLCAiYXJlYV9yYXN0ZXJhcmVhIl0gPC0gc2VnbWVudF9hcmVhX3Jhc3RlcgogICAgCiAgI2NvbnZlcnQgdG8gc3BhdGlhbCBwb2x5Z29ucyB0byBjaGVjayBhcmVhIGNhbGN1bGF0aW9ucwogICAgCiAgI2NvbnZlcnQgc2VnbWVudCBmcm9tIHJhc3RlciB0byBwb2x5Z29uLCBlYWNoIGNlbGwgZnJvbSB0aGUgcmFzdGVyIGlzIGFuIGluZGVwZW5kZW50IHBvbHlnb24sIChkaXNzb2x2ZSBtZWFucyBhbGwgY2VsbHMgd2l0aCBhIHZhbHVlIG9mIDEgYXJlIGEgc2luZ2xlIHBvbHlnb24gaWYgY29ubmVjdGVkKQogIHNlZ21lbnRfbm9ydGguc3AgPC0gcmFzdGVyVG9Qb2x5Z29ucyhzZWdtZW50X25vcnRoLCBkaXNzb2x2ZSA9IFQpCiAgCiAgIyAgSWYgeCBpcyBhIFNwYXRpYWxQb2x5Z29ucyogb2JqZWN0OiBhcmVhIG9mIGVhY2ggc3BhdGlhbCBvYmplY3QgaW4gc3F1YXJlZCBtZXRlcnMgaWYgdGhlIENSUyBpcyBsb25naXR1ZGUvbGF0aXR1ZGUsIG9yIGluIHNxdWFyZWQgbWFwIHVuaXRzICh0eXBpY2FsbHkgbWV0ZXIpCiAgCiAgICAjcHJvamVjdCB0byBlcXVhbCBlYXJ0aCBhcmVhIHByb2plY3Rpb24KICBzZWdtZW50X25vcnRoLnNwLkVBIDwtIHNwVHJhbnNmb3JtKHNlZ21lbnRfbm9ydGguc3AsIENSU29iaiA9IGVxdWFsYXJlYXByb2plY3Rpb24pCgogICNjYWxjdWxhdGUgYXJlYSBvZiB0aGUgc3BhdGlhbCBvYmplY3QgaW4gbV4yCiAgICBwb2x5Z29uX3NpemUuc3AgPC0gYXJlYShzZWdtZW50X25vcnRoLnNwLkVBKQoKICAgICNjb252ZXJ0IGZyb20gbV4yIHRvIGttXjIKICAgIHNlZ21lbnRfYXJlYV9lcXVhbGFyZWEgPC0gcG9seWdvbl9zaXplLnNwLzFlNgoKICAgICNwb3B1bGF0ZSBkYXRhIHRhYmxlIHdpdGggcG9seWdvbiBhcmVhIHVzaW5nIHJhc3RlciBjYWxjdWxhdGlvbgogIGVhc3RfcGFjX3NoZWxmX2FyZWFzW2ksICJhcmVhX2VxdWFsYXJlYXByb2oiXSA8LSBzZWdtZW50X2FyZWFfZXF1YWxhcmVhCiAgCiAgI2FuZCB0aGVuIHBsYWluIGFuZCBzaW1wbGUgYWxzbyB1c2luZyByZ2Vvczo6Z0FyZWEKICAKICBhcmVhX3JnZW9zX2dBcmVhIDwtIGdBcmVhKHNlZ21lbnRfbm9ydGguc3AuRUEpLzFlNgogIAogICNwb3B1bGF0ZSBkYXRhIHRhYmxlIHdpdGggcG9seWdvbiBhcmVhIHVzaW5nIHJlZ2VvcyBjYWxjdWxhdGlvbgogIGVhc3RfcGFjX3NoZWxmX2FyZWFzW2ksICJhcmVhX3JnZW9zX2dBcmVhIl0gPC0gICBhcmVhX3JnZW9zX2dBcmVhCiAgCiAgcHJpbnQoaSkKICB9IAp9CgojbG9vcCBmb3Igc291dGgKZm9yIChpIGluIDE6KGxlbmd0aChlYXN0X3BhY19zb3V0aF9sYXRpdHVkZXMpLTEpKSB7CiAgc291dGhfZXh0ZW50IDwtIGMoeG1pbih3ZXN0X2luZF9zcGRmX21hc2tfMXMpLCB4bWF4KHdlc3RfaW5kX3NwZGZfbWFza18xcyksIGVhc3RfcGFjX3NvdXRoX2xhdGl0dWRlc1tpKzFdLCBlYXN0X3BhY19zb3V0aF9sYXRpdHVkZXNbaV0pICNvcmRlcj0geG1pbiwgeG1heCwgeW1pbiwgeW1heCkKICAKICAjcmFzdGVyIHNlZ21lbnQKICBzZWdtZW50X3NvdXRoIDwtIGNyb3Aod2VzdF9pbmRfc3BkZl9tYXNrXzFzLCBleHRlbnQoc291dGhfZXh0ZW50KSkKICAKICAjYWRkIGxhdGl0dWRlIGJpbiBpbmZvIHRvIGRhdGEgdGFibGUKICAgIGVhc3RfcGFjX3NoZWxmX2FyZWFzW2krKGxlbmd0aChlYXN0X3BhY19ub3J0aF9sYXRpdHVkZXMpLTEpLCAibGF0aXR1ZGVfc3RhcnQiXSA8LSBlYXN0X3BhY19zb3V0aF9sYXRpdHVkZXNbaV0KICBlYXN0X3BhY19zaGVsZl9hcmVhc1tpKyhsZW5ndGgoZWFzdF9wYWNfbm9ydGhfbGF0aXR1ZGVzKS0xKSwgImxhdGl0dWRlX2VuZCJdIDwtIGVhc3RfcGFjX3NvdXRoX2xhdGl0dWRlc1tpKzFdCiAgCiAgCiAgaWYoYWxsKGlzLm5hKHZhbHVlcyhzZWdtZW50X3NvdXRoKSkpKSB7ICNpZiB0aGVyZSdzIG5vIHNoZWxmIGFyZWEgd2l0aGluIGEgYmluLCBtZWFuaW5nIHRoZXJlJ3Mgbm8gc2hlbGYgYXJlYSBhdCB0aGF0IGxhdGl0dWRlCgogIGVhc3RfcGFjX3NoZWxmX2FyZWFzW2krKGxlbmd0aChlYXN0X3BhY19ub3J0aF9sYXRpdHVkZXMpLTEpLCAiYXJlYV9lcXVhbGFyZWFwcm9qIl0gPC0gMAogIGVhc3RfcGFjX3NoZWxmX2FyZWFzW2krKGxlbmd0aChlYXN0X3BhY19ub3J0aF9sYXRpdHVkZXMpLTEpLCAiYXJlYV9yYXN0ZXJhcmVhIl0gPC0gMAogICAgZWFzdF9wYWNfc2hlbGZfYXJlYXNbaSsobGVuZ3RoKGVhc3RfcGFjX25vcnRoX2xhdGl0dWRlcyktMSksICJhcmVhX3JnZW9zX2dBcmVhIl0gPC0gMAogIAogIHByaW50KGkpCiAgICAKICB9IGVsc2UgewogIAogICAgI3Jhc3RlciBhcmVhIGNhbGN1bGF0aW9uCiAgICAgICNnZXQgc2l6ZXMgb2YgYWxsIGNlbGxzIGluIHJhc3RlciBba20yXQogICAgY2VsbF9zaXplX3Jhc3RlcjwtYXJlYShzZWdtZW50X3NvdXRoLCBuYS5ybT1UUlVFLCB3ZWlnaHRzPUZBTFNFKQogICAgCiAgICAjZGVsZXRlIE5BcyBmcm9tIHZlY3RvciBvZiBhbGwgcmFzdGVyIGNlbGxzCiAgICBjZWxsX3NpemVfcmFzdGVyPC1jZWxsX3NpemVfcmFzdGVyWyFpcy5uYShzZWdtZW50X3NvdXRoKV0KICAgICNjb21wdXRlIGFyZWEgb2YgYWxsIGNlbGxzIGluIGdlb19yYXN0ZXIKICAgICNmdWxsIGFyZWEgICAgICAgICAgPC0gdG90YWwgIyBncmlkIGNlbGxzICAgICAqIG1lZGlhbiBjZWxsIGFyZWEgKHVzaW5nIG1lZGlhbiBjYXJlcyBsZXNzIGFib3V0IGV4dHJlbWUgdmFsdWVzKQogICAgc2VnbWVudF9hcmVhX3Jhc3RlciA8LSBsZW5ndGgoY2VsbF9zaXplX3Jhc3RlcikqbWVkaWFuKGNlbGxfc2l6ZV9yYXN0ZXIpCiAgICAKICAjcG9wdWxhdGUgZGF0YSB0YWJsZSB3aXRoIHJhc3RlciBhcmVhCiAgZWFzdF9wYWNfc2hlbGZfYXJlYXNbaSsobGVuZ3RoKGVhc3RfcGFjX25vcnRoX2xhdGl0dWRlcyktMSksICJhcmVhX3Jhc3RlcmFyZWEiXSA8LSBzZWdtZW50X2FyZWFfcmFzdGVyCiAgICAKICAKICAjY29udmVydCB0byBzcGF0aWFsIHBvbHlnb25zIHRvIGNoZWNrIGFyZWEgY2FsY3VsYXRpb25zCiAgICAKICAjY29udmVydCBzZWdtZW50IGZyb20gcmFzdGVyIHRvIHBvbHlnb24sIGVhY2ggY2VsbCBmcm9tIHRoZSByYXN0ZXIgaXMgYW4gaW5kZXBlbmRlbnQgcG9seWdvbiwgKGRpc3NvbHZlIG1lYW5zIGFsbCBjZWxscyB3aXRoIGEgdmFsdWUgb2YgMSBhcmUgYSBzaW5nbGUgcG9seWdvbiBpZiBjb25uZWN0ZWQpCiAgc2VnbWVudF9zb3V0aC5zcCA8LSByYXN0ZXJUb1BvbHlnb25zKHNlZ21lbnRfc291dGgsIGRpc3NvbHZlID0gVCkKICAKICAjICBJZiB4IGlzIGEgU3BhdGlhbFBvbHlnb25zKiBvYmplY3Q6IGFyZWEgb2YgZWFjaCBzcGF0aWFsIG9iamVjdCBpbiBzcXVhcmVkIG1ldGVycyBpZiB0aGUgQ1JTIGlzIGxvbmdpdHVkZS9sYXRpdHVkZSwgb3IgaW4gc3F1YXJlZCBtYXAgdW5pdHMgKHR5cGljYWxseSBtZXRlcikKICAKICAgICNwcm9qZWN0IHRvIGVxdWFsIGVhcnRoIGFyZWEgcHJvamVjdGlvbgogIHNlZ21lbnRfc291dGguc3AuRUEgPC0gc3BUcmFuc2Zvcm0oc2VnbWVudF9zb3V0aC5zcCwgQ1JTb2JqID0gZXF1YWxhcmVhcHJvamVjdGlvbikKCiAgI2NhbGN1bGF0ZSBhcmVhIG9mIHRoZSBzcGF0aWFsIG9iamVjdCBpbiBtXjIKICAgIHBvbHlnb25fc2l6ZS5zcCA8LSBhcmVhKHNlZ21lbnRfc291dGguc3AuRUEpCgogICAgI2NvbnZlcnQgZnJvbSBtXjIgdG8ga21eMgogICAgc2VnbWVudF9hcmVhX2VxdWFsYXJlYSA8LSBwb2x5Z29uX3NpemUuc3AvMWU2CgogICAgI3BvcHVsYXRlIGRhdGEgdGFibGUgd2l0aCBhcmVhIG9mIHBvbHlnb24gZnJvbSByYXN0ZXI6OmFyZWEgZnVuY3Rpb24KICBlYXN0X3BhY19zaGVsZl9hcmVhc1tpKyhsZW5ndGgoZWFzdF9wYWNfbm9ydGhfbGF0aXR1ZGVzKS0xKSwgImFyZWFfZXF1YWxhcmVhcHJvaiJdIDwtIHNlZ21lbnRfYXJlYV9lcXVhbGFyZWEKICAKICAjYW5kIHRoZW4gcGxhaW4gYW5kIHNpbXBsZSBhbHNvIHVzaW5nIHJnZW9zOjpnQXJlYQogIAogIGFyZWFfcmdlb3NfZ0FyZWEgPC0gZ0FyZWEoc2VnbWVudF9zb3V0aC5zcC5FQSkvMWU2CiAgCiAgI3BvcHVsYXRlIGRhdGEgdGFibGUgZnJvbSByZ2VvcyBhcmVhIGNhbGN1bGF0aW9uIGZvciBwcm9qZWN0ZWQgcG9seWdvbgogIGVhc3RfcGFjX3NoZWxmX2FyZWFzW2krKGxlbmd0aChlYXN0X3BhY19ub3J0aF9sYXRpdHVkZXMpLTEpLCAiYXJlYV9yZ2Vvc19nQXJlYSJdIDwtICAgYXJlYV9yZ2Vvc19nQXJlYQogIAogIHByaW50KGkpCiAgfSAKfQoKI2NvbXBhcmUgcmFzdGVyOmFyZWEgY2FsY3VsYXRpb24sIHRvIGVxdWFsIGFyZWEgc3RpbGwgdXNpbmcgcmFzdGVyOjphcmVhIGZ1bmN0aW9uLCB0byByZ2Vvczo6Z0FyZWEgZnVuY3Rpb24gZm9yIHBvbHlnb25zCgpnZ3Bsb3QoZGF0YSA9IGVhc3RfcGFjX3NoZWxmX2FyZWFzKSArCiAgZ2VvbV9wb2ludChhZXMoeCA9IGxhdGl0dWRlX3N0YXJ0LCB5ID0gYXJlYV9yZ2Vvc19nQXJlYSksIGNvbG9yID0gInB1cnBsZSIsIHNpemUgPSAwLjUpICsKICBnZW9tX3BvaW50KGFlcyh4ID0gbGF0aXR1ZGVfc3RhcnQsIHkgPSBhcmVhX3Jhc3RlcmFyZWEpLCBjb2xvciA9ICJkYXJrZ3JlZW4iLCBzaXplID0gMC41KSArCiAgZ2VvbV9wb2ludChhZXMoeCA9IGxhdGl0dWRlX3N0YXJ0LCB5ID0gYXJlYV9lcXVhbGFyZWFwcm9qKSwgY29sb3IgPSAicmVkIiwgc2l6ZSA9IDAuNSkgKwogIGxhYnMoeCA9ICJMYXRpdHVkZSIsIHkgPSAiQXJlYSBrbV4yIikgKwogIHRoZW1lX2NsYXNzaWMoKQoKY29yKGVhc3RfcGFjX3NoZWxmX2FyZWFzWywzOjVdLCB1c2UgPSAiY29tcGxldGUub2JzIikKCnNhdmUoZWFzdF9wYWNfc2hlbGZfYXJlYXMsIGZpbGUgPSAiZWFzdF9wYWNfc2hlbGZfYXJlYXMuUkRhdGEiKQoKYGBgCgpgYGB7ciBwZXJjZW50IHNoaWZ0IGVhc3Rlcm4gcGFjaWZpY30KZWFzdF9wYWNfc2hlbGZfYXJlYXNbLCBwZXJjZW50X2NoYW5nZSA6PSAoYXJlYV9lcXVhbGFyZWFwcm9qLXNoaWZ0KGFyZWFfZXF1YWxhcmVhcHJvaiwgdHlwZSA9ICJsYWciKSkvc2hpZnQoYXJlYV9lcXVhbGFyZWFwcm9qLCB0eXBlID0gImxhZyIpXVssYXJlYV8xMDAwcyA6PSBhcmVhX2VxdWFsYXJlYXByb2ovMTAwMF0KCmVhc3RfcGFjX3NoZWxmX2FyZWFzWywgY2hhbmdlX2Fib3ZlXzJmb2xkIDo9IGlmZWxzZSgocGVyY2VudF9jaGFuZ2U+PTEgJiBwZXJjZW50X2NoYW5nZTxJbmYpLCAxLCBpZmVsc2UocGVyY2VudF9jaGFuZ2U8PS0wLjUsIC0xLCAwKSldCgplYXN0X3BhY19zaGVsZl9hcmVhc19oaWdobGlnaHQgPC0gZWFzdF9wYWNfc2hlbGZfYXJlYXNbY2hhbmdlX2Fib3ZlXzJmb2xkICE9IDAsXQoKZWFzdF9wYWNfc2hlbGZfYXJlYXNfc3RhdHMgPC0gdGFibGUoZWFzdF9wYWNfc2hlbGZfYXJlYXNbLC4oY2hhbmdlX2Fib3ZlXzJmb2xkKV0pCmBgYAoKV2VzdGVybiBBdGxhbnRpYwoKd2VzdF9hdGxfc3BkZl9tYXNrCgpgYGB7ciBzcGxpdCByYXN0ZXIgZm9yIHdlc3Rlcm4gYXRsYW50aWN9Cm5vcnRoX2V4dGVudCA8LSBjKHhtaW4od2VzdF9hdGxfc3BkZl9tYXNrXzFzKSwgeG1heCh3ZXN0X2F0bF9zcGRmX21hc2tfMXMpLCAwLCB5bWF4KHdlc3RfYXRsX3NwZGZfbWFza18xcykpCnNvdXRoX2V4dGVudCA8LSBjKHhtaW4od2VzdF9hdGxfc3BkZl9tYXNrXzFzKSwgeG1heCh3ZXN0X2F0bF9zcGRmX21hc2tfMXMpLCB5bWluKHdlc3RfYXRsX3NwZGZfbWFza18xcyksIDApCgojY3JvcCB3ZXN0X2F0bCByYXN0ZXIgYWJvdmUgYW5kIGJlbG93IDAKd2VzdF9hdGxfc3BkZl9zaGlmdF9hZ2dfbm9ydGggPC0gY3JvcCh3ZXN0X2F0bF9zcGRmX21hc2tfMXMsIGV4dGVudChub3J0aF9leHRlbnQpKQoKd2VzdF9hdGxfc3BkZl9zaGlmdF9hZ2dfc291dGggPC0gY3JvcCh3ZXN0X2F0bF9zcGRmX21hc2tfMXMsIGV4dGVudChzb3V0aF9leHRlbnQpKQoKI3VuZm9ydHVuYXRlbHksIEkgdGhpbmsgSSBtYXkgaGF2ZSB0byBqdXN0IGRvIHRoaXMgbWFudWFsbHkgKHVnbHksIEkga25vdykKCiNhbGwgY2h1bmtzIGZvciB3ZXN0IGF0bGFudGljCndlc3RfYXRsX25vcnRoX2xhdGl0dWRlcyA8LSBzZXEoMCwgeW1heCh3ZXN0X2F0bF9zcGRmX21hc2tfMXMpLCBieSA9IDEpCndlc3RfYXRsX3NvdXRoX2xhdGl0dWRlcyA8LSBzZXEoMCwgeW1pbih3ZXN0X2F0bF9zcGRmX21hc2tfMXMpLCBieSA9IC0xKQoKI3NldHVwIGRhdGEgdGFibGUgdG8gcG9wdWxhdGUgaW4gbG9vcCwgc3VidHJhY3Rpbmcgb25lIHRvIGFsbG93IGZvciBiaW5zCndlc3RfYXRsX3NoZWxmX2FyZWFzIDwtIGFzLmRhdGEudGFibGUobWF0cml4KG5yb3cgPSAobGVuZ3RoKHdlc3RfYXRsX25vcnRoX2xhdGl0dWRlcyktMStsZW5ndGgod2VzdF9hdGxfc291dGhfbGF0aXR1ZGVzKS0xKSkpCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCndlc3RfYXRsX3NoZWxmX2FyZWFzWywgbGF0aXR1ZGVfc3RhcnQgOj0gYXMubnVtZXJpYyhWMSldWywgbGF0aXR1ZGVfZW5kIDo9IGFzLm51bWVyaWMoVjEpXVssIGFyZWFfcmFzdGVyYXJlYSA6PSBhcy5udW1lcmljKFYxKV1bLCBhcmVhX2VxdWFsYXJlYXByb2ogOj0gYXMubnVtZXJpYyhWMSldWywgYXJlYV9yZ2Vvc19nQXJlYSA6PSBhcy5udW1lcmljKFYxKV1bLCBWMSA6PSBOVUxMXQoKI2xvb3AgZm9yIG5vcnRoCmZvciAoaSBpbiAxOihsZW5ndGgod2VzdF9hdGxfbm9ydGhfbGF0aXR1ZGVzKS0xKSkgewogICNzZXR0aW5nIHVwIGV4dGVudCBmb3Igc2xpY2luZyBieSBtaW4gYW5kIG1heCBsb25naXR1ZGVzLCBhbmQgaSB0byBpKzEgbGF0aXR1ZGVzCiAgbm9ydGhfZXh0ZW50IDwtIGMoeG1pbih3ZXN0X2F0bF9zcGRmX21hc2tfMXMpLCB4bWF4KHdlc3RfYXRsX3NwZGZfbWFza18xcyksIHdlc3RfYXRsX25vcnRoX2xhdGl0dWRlc1tpXSwgd2VzdF9hdGxfbm9ydGhfbGF0aXR1ZGVzW2krMV0pCiAgCiAgI2Nyb3AgcmFzdGVyIHNlZ2VtZW50IGJhc2VkIG9uIGJpbiBleHRlbnQKICBzZWdtZW50X25vcnRoIDwtIGNyb3Aod2VzdF9hdGxfc3BkZl9tYXNrXzFzLCBleHRlbnQobm9ydGhfZXh0ZW50KSkKICAKICAjcG9wdWxhdGUgZGF0YSB0YWJsZSB3aXRoIGxhdGl0dWRpbmFsIGJpbgogIHdlc3RfYXRsX3NoZWxmX2FyZWFzW2ksICJsYXRpdHVkZV9zdGFydCJdIDwtIHdlc3RfYXRsX25vcnRoX2xhdGl0dWRlc1tpXQogIHdlc3RfYXRsX3NoZWxmX2FyZWFzW2ksICJsYXRpdHVkZV9lbmQiXSA8LSB3ZXN0X2F0bF9ub3J0aF9sYXRpdHVkZXNbaSsxXQogIAogIGlmKGFsbChpcy5uYSh2YWx1ZXMoc2VnbWVudF9ub3J0aCkpKSkgeyAjaWYgdGhlcmUncyBubyBzaGVsZiBhcmVhIHdpdGhpbiBhIGJpbiwgYWxsIGFyZWEgPSAwCiAgICAKICB3ZXN0X2F0bF9zaGVsZl9hcmVhc1tpLCAiYXJlYV9lcXVhbGFyZWFwcm9qIl0gPC0gMAogIHdlc3RfYXRsX3NoZWxmX2FyZWFzW2ksICJhcmVhX3Jhc3RlcmFyZWEiXSA8LSAwCiAgd2VzdF9hdGxfc2hlbGZfYXJlYXNbaSwgImFyZWFfcmdlb3NfZ0FyZWEiXSA8LSAwCgogIAogIHByaW50KGkpCiAgICAKICB9IGVsc2UgeyAjaWYgdGhlcmUgaXMgc2hlbGYgYXJlYSB3aXRoaW4gdGhlIGJpbiwgY2FsY3VsYXRlIGFyZWEgb2Ygc2xpY2UKICAKICAgICNyYXN0ZXIgYXJlYSBjYWxjdWxhdGlvbgogICAgICAjZ2V0IHNpemVzIG9mIGFsbCBjZWxscyBpbiByYXN0ZXIgW2ttMl0KICAgIGNlbGxfc2l6ZV9yYXN0ZXI8LWFyZWEoc2VnbWVudF9ub3J0aCwgbmEucm09VFJVRSwgd2VpZ2h0cz1GQUxTRSkKICAgIAogICAgI2RlbGV0ZSBOQXMgZnJvbSB2ZWN0b3Igb2YgYWxsIHJhc3RlciBjZWxscwogICAgY2VsbF9zaXplX3Jhc3RlcjwtY2VsbF9zaXplX3Jhc3RlclshaXMubmEoc2VnbWVudF9ub3J0aCldCiAgICAKICAgICNjb21wdXRlIGFyZWEgb2YgYWxsIGNlbGxzIGluIGdlb19yYXN0ZXIKICAgICNmdWxsIGFyZWEgICAgICAgICAgPC0gdG90YWwgIyBncmlkIGNlbGxzICAgICAqIG1lZGlhbiBjZWxsIGFyZWEgKHVzaW5nIG1lZGlhbiBjYXJlcyBsZXNzIGFib3V0IGV4dHJlbWUgdmFsdWVzKQogICAgc2VnbWVudF9hcmVhX3Jhc3RlciA8LSBsZW5ndGgoY2VsbF9zaXplX3Jhc3RlcikqbWVkaWFuKGNlbGxfc2l6ZV9yYXN0ZXIpICNpbiBrbV4yCiAgICAKICAjcG9wdWxhdGUgZGF0YSB0YWJsZSB3aXRoIHJhc3RlciBhcmVhCiAgd2VzdF9hdGxfc2hlbGZfYXJlYXNbaSwgImFyZWFfcmFzdGVyYXJlYSJdIDwtIHNlZ21lbnRfYXJlYV9yYXN0ZXIKICAgIAogICNjb252ZXJ0IHRvIHNwYXRpYWwgcG9seWdvbnMgdG8gY2hlY2sgYXJlYSBjYWxjdWxhdGlvbnMKICAgIAogICNjb252ZXJ0IHNlZ21lbnQgZnJvbSByYXN0ZXIgdG8gcG9seWdvbiwgZWFjaCBjZWxsIGZyb20gdGhlIHJhc3RlciBpcyBhbiBpbmRlcGVuZGVudCBwb2x5Z29uLCAoZGlzc29sdmUgbWVhbnMgYWxsIGNlbGxzIHdpdGggYSB2YWx1ZSBvZiAxIGFyZSBhIHNpbmdsZSBwb2x5Z29uIGlmIGNvbm5lY3RlZCkKICBzZWdtZW50X25vcnRoLnNwIDwtIHJhc3RlclRvUG9seWdvbnMoc2VnbWVudF9ub3J0aCwgZGlzc29sdmUgPSBUKQogIAogICMgIElmIHggaXMgYSBTcGF0aWFsUG9seWdvbnMqIG9iamVjdDogYXJlYSBvZiBlYWNoIHNwYXRpYWwgb2JqZWN0IGluIHNxdWFyZWQgbWV0ZXJzIGlmIHRoZSBDUlMgaXMgbG9uZ2l0dWRlL2xhdGl0dWRlLCBvciBpbiBzcXVhcmVkIG1hcCB1bml0cyAodHlwaWNhbGx5IG1ldGVyKQogIAogICAgI3Byb2plY3QgdG8gZXF1YWwgZWFydGggYXJlYSBwcm9qZWN0aW9uCiAgc2VnbWVudF9ub3J0aC5zcC5FQSA8LSBzcFRyYW5zZm9ybShzZWdtZW50X25vcnRoLnNwLCBDUlNvYmogPSBlcXVhbGFyZWFwcm9qZWN0aW9uKQoKICAjY2FsY3VsYXRlIGFyZWEgb2YgdGhlIHNwYXRpYWwgb2JqZWN0IGluIG1eMgogICAgcG9seWdvbl9zaXplLnNwIDwtIGFyZWEoc2VnbWVudF9ub3J0aC5zcC5FQSkKCiAgICAjY29udmVydCBmcm9tIG1eMiB0byBrbV4yCiAgICBzZWdtZW50X2FyZWFfZXF1YWxhcmVhIDwtIHBvbHlnb25fc2l6ZS5zcC8xZTYKCiAgICAjcG9wdWxhdGUgZGF0YSB0YWJsZSB3aXRoIHBvbHlnb24gYXJlYSB1c2luZyByYXN0ZXIgY2FsY3VsYXRpb24KICB3ZXN0X2F0bF9zaGVsZl9hcmVhc1tpLCAiYXJlYV9lcXVhbGFyZWFwcm9qIl0gPC0gc2VnbWVudF9hcmVhX2VxdWFsYXJlYQogIAogICNhbmQgdGhlbiBwbGFpbiBhbmQgc2ltcGxlIGFsc28gdXNpbmcgcmdlb3M6OmdBcmVhCiAgCiAgYXJlYV9yZ2Vvc19nQXJlYSA8LSBnQXJlYShzZWdtZW50X25vcnRoLnNwLkVBKS8xZTYKICAKICAjcG9wdWxhdGUgZGF0YSB0YWJsZSB3aXRoIHBvbHlnb24gYXJlYSB1c2luZyByZWdlb3MgY2FsY3VsYXRpb24KICB3ZXN0X2F0bF9zaGVsZl9hcmVhc1tpLCAiYXJlYV9yZ2Vvc19nQXJlYSJdIDwtICAgYXJlYV9yZ2Vvc19nQXJlYQogIAogIHByaW50KGkpCiAgfSAKfQoKI2xvb3AgZm9yIHNvdXRoCmZvciAoaSBpbiAxOihsZW5ndGgod2VzdF9hdGxfc291dGhfbGF0aXR1ZGVzKS0xKSkgewogIHNvdXRoX2V4dGVudCA8LSBjKHhtaW4od2VzdF9hdGxfc3BkZl9tYXNrXzFzKSwgeG1heCh3ZXN0X2F0bF9zcGRmX21hc2tfMXMpLCB3ZXN0X2F0bF9zb3V0aF9sYXRpdHVkZXNbaSsxXSwgd2VzdF9hdGxfc291dGhfbGF0aXR1ZGVzW2ldKSAjb3JkZXI9IHhtaW4sIHhtYXgsIHltaW4sIHltYXgpCiAgCiAgI3Jhc3RlciBzZWdtZW50CiAgc2VnbWVudF9zb3V0aCA8LSBjcm9wKHdlc3RfYXRsX3NwZGZfbWFza18xcywgZXh0ZW50KHNvdXRoX2V4dGVudCkpCiAgCiAgI2FkZCBsYXRpdHVkZSBiaW4gaW5mbyB0byBkYXRhIHRhYmxlCiAgICB3ZXN0X2F0bF9zaGVsZl9hcmVhc1tpKyhsZW5ndGgod2VzdF9hdGxfbm9ydGhfbGF0aXR1ZGVzKS0xKSwgImxhdGl0dWRlX3N0YXJ0Il0gPC0gd2VzdF9hdGxfc291dGhfbGF0aXR1ZGVzW2ldCiAgd2VzdF9hdGxfc2hlbGZfYXJlYXNbaSsobGVuZ3RoKHdlc3RfYXRsX25vcnRoX2xhdGl0dWRlcyktMSksICJsYXRpdHVkZV9lbmQiXSA8LSB3ZXN0X2F0bF9zb3V0aF9sYXRpdHVkZXNbaSsxXQogIAogIAogIGlmKGFsbChpcy5uYSh2YWx1ZXMoc2VnbWVudF9zb3V0aCkpKSkgeyAjaWYgdGhlcmUncyBubyBzaGVsZiBhcmVhIHdpdGhpbiBhIGJpbiwgbWVhbmluZyB0aGVyZSdzIG5vIHNoZWxmIGFyZWEgYXQgdGhhdCBsYXRpdHVkZQoKICB3ZXN0X2F0bF9zaGVsZl9hcmVhc1tpKyhsZW5ndGgod2VzdF9hdGxfbm9ydGhfbGF0aXR1ZGVzKS0xKSwgImFyZWFfZXF1YWxhcmVhcHJvaiJdIDwtIDAKICB3ZXN0X2F0bF9zaGVsZl9hcmVhc1tpKyhsZW5ndGgod2VzdF9hdGxfbm9ydGhfbGF0aXR1ZGVzKS0xKSwgImFyZWFfcmFzdGVyYXJlYSJdIDwtIDAKICAgIHdlc3RfYXRsX3NoZWxmX2FyZWFzW2krKGxlbmd0aCh3ZXN0X2F0bF9ub3J0aF9sYXRpdHVkZXMpLTEpLCAiYXJlYV9yZ2Vvc19nQXJlYSJdIDwtIDAKICAKICBwcmludChpKQogICAgCiAgfSBlbHNlIHsKICAKICAgICNyYXN0ZXIgYXJlYSBjYWxjdWxhdGlvbgogICAgICAjZ2V0IHNpemVzIG9mIGFsbCBjZWxscyBpbiByYXN0ZXIgW2ttMl0KICAgIGNlbGxfc2l6ZV9yYXN0ZXI8LWFyZWEoc2VnbWVudF9zb3V0aCwgbmEucm09VFJVRSwgd2VpZ2h0cz1GQUxTRSkKICAgIAogICAgI2RlbGV0ZSBOQXMgZnJvbSB2ZWN0b3Igb2YgYWxsIHJhc3RlciBjZWxscwogICAgY2VsbF9zaXplX3Jhc3RlcjwtY2VsbF9zaXplX3Jhc3RlclshaXMubmEoc2VnbWVudF9zb3V0aCldCiAgICAjY29tcHV0ZSBhcmVhIG9mIGFsbCBjZWxscyBpbiBnZW9fcmFzdGVyCiAgICAjZnVsbCBhcmVhICAgICAgICAgIDwtIHRvdGFsICMgZ3JpZCBjZWxscyAgICAgKiBtZWRpYW4gY2VsbCBhcmVhICh1c2luZyBtZWRpYW4gY2FyZXMgbGVzcyBhYm91dCBleHRyZW1lIHZhbHVlcykKICAgIHNlZ21lbnRfYXJlYV9yYXN0ZXIgPC0gbGVuZ3RoKGNlbGxfc2l6ZV9yYXN0ZXIpKm1lZGlhbihjZWxsX3NpemVfcmFzdGVyKQogICAgCiAgI3BvcHVsYXRlIGRhdGEgdGFibGUgd2l0aCByYXN0ZXIgYXJlYQogIHdlc3RfYXRsX3NoZWxmX2FyZWFzW2krKGxlbmd0aCh3ZXN0X2F0bF9ub3J0aF9sYXRpdHVkZXMpLTEpLCAiYXJlYV9yYXN0ZXJhcmVhIl0gPC0gc2VnbWVudF9hcmVhX3Jhc3RlcgogICAgCiAgCiAgI2NvbnZlcnQgdG8gc3BhdGlhbCBwb2x5Z29ucyB0byBjaGVjayBhcmVhIGNhbGN1bGF0aW9ucwogICAgCiAgI2NvbnZlcnQgc2VnbWVudCBmcm9tIHJhc3RlciB0byBwb2x5Z29uLCBlYWNoIGNlbGwgZnJvbSB0aGUgcmFzdGVyIGlzIGFuIGluZGVwZW5kZW50IHBvbHlnb24sIChkaXNzb2x2ZSBtZWFucyBhbGwgY2VsbHMgd2l0aCBhIHZhbHVlIG9mIDEgYXJlIGEgc2luZ2xlIHBvbHlnb24gaWYgY29ubmVjdGVkKQogIHNlZ21lbnRfc291dGguc3AgPC0gcmFzdGVyVG9Qb2x5Z29ucyhzZWdtZW50X3NvdXRoLCBkaXNzb2x2ZSA9IFQpCiAgCiAgIyAgSWYgeCBpcyBhIFNwYXRpYWxQb2x5Z29ucyogb2JqZWN0OiBhcmVhIG9mIGVhY2ggc3BhdGlhbCBvYmplY3QgaW4gc3F1YXJlZCBtZXRlcnMgaWYgdGhlIENSUyBpcyBsb25naXR1ZGUvbGF0aXR1ZGUsIG9yIGluIHNxdWFyZWQgbWFwIHVuaXRzICh0eXBpY2FsbHkgbWV0ZXIpCiAgCiAgICAjcHJvamVjdCB0byBlcXVhbCBlYXJ0aCBhcmVhIHByb2plY3Rpb24KICBzZWdtZW50X3NvdXRoLnNwLkVBIDwtIHNwVHJhbnNmb3JtKHNlZ21lbnRfc291dGguc3AsIENSU29iaiA9IGVxdWFsYXJlYXByb2plY3Rpb24pCgogICNjYWxjdWxhdGUgYXJlYSBvZiB0aGUgc3BhdGlhbCBvYmplY3QgaW4gbV4yCiAgICBwb2x5Z29uX3NpemUuc3AgPC0gYXJlYShzZWdtZW50X3NvdXRoLnNwLkVBKQoKICAgICNjb252ZXJ0IGZyb20gbV4yIHRvIGttXjIKICAgIHNlZ21lbnRfYXJlYV9lcXVhbGFyZWEgPC0gcG9seWdvbl9zaXplLnNwLzFlNgoKICAgICNwb3B1bGF0ZSBkYXRhIHRhYmxlIHdpdGggYXJlYSBvZiBwb2x5Z29uIGZyb20gcmFzdGVyOjphcmVhIGZ1bmN0aW9uCiAgd2VzdF9hdGxfc2hlbGZfYXJlYXNbaSsobGVuZ3RoKHdlc3RfYXRsX25vcnRoX2xhdGl0dWRlcyktMSksICJhcmVhX2VxdWFsYXJlYXByb2oiXSA8LSBzZWdtZW50X2FyZWFfZXF1YWxhcmVhCiAgCiAgI2FuZCB0aGVuIHBsYWluIGFuZCBzaW1wbGUgYWxzbyB1c2luZyByZ2Vvczo6Z0FyZWEKICAKICBhcmVhX3JnZW9zX2dBcmVhIDwtIGdBcmVhKHNlZ21lbnRfc291dGguc3AuRUEpLzFlNgogIAogICNwb3B1bGF0ZSBkYXRhIHRhYmxlIGZyb20gcmdlb3MgYXJlYSBjYWxjdWxhdGlvbiBmb3IgcHJvamVjdGVkIHBvbHlnb24KICB3ZXN0X2F0bF9zaGVsZl9hcmVhc1tpKyhsZW5ndGgod2VzdF9hdGxfbm9ydGhfbGF0aXR1ZGVzKS0xKSwgImFyZWFfcmdlb3NfZ0FyZWEiXSA8LSAgIGFyZWFfcmdlb3NfZ0FyZWEKICAKICBwcmludChpKQogIH0gCn0KCiNjb21wYXJlIHJhc3RlcjphcmVhIGNhbGN1bGF0aW9uLCB0byBlcXVhbCBhcmVhIHN0aWxsIHVzaW5nIHJhc3Rlcjo6YXJlYSBmdW5jdGlvbiwgdG8gcmdlb3M6OmdBcmVhIGZ1bmN0aW9uIGZvciBwb2x5Z29ucwoKZ2dwbG90KGRhdGEgPSB3ZXN0X2F0bF9zaGVsZl9hcmVhcykgKwogIGdlb21fcG9pbnQoYWVzKHggPSBsYXRpdHVkZV9zdGFydCwgeSA9IGFyZWFfcmdlb3NfZ0FyZWEpLCBjb2xvciA9ICJwdXJwbGUiLCBzaXplID0gMC41KSArCiAgZ2VvbV9wb2ludChhZXMoeCA9IGxhdGl0dWRlX3N0YXJ0LCB5ID0gYXJlYV9yYXN0ZXJhcmVhKSwgY29sb3IgPSAiZGFya2dyZWVuIiwgc2l6ZSA9IDAuNSkgKwogIGdlb21fcG9pbnQoYWVzKHggPSBsYXRpdHVkZV9zdGFydCwgeSA9IGFyZWFfZXF1YWxhcmVhcHJvaiksIGNvbG9yID0gInJlZCIsIHNpemUgPSAwLjUpICsKICBsYWJzKHggPSAiTGF0aXR1ZGUiLCB5ID0gIkFyZWEga21eMiIpICsKICB0aGVtZV9jbGFzc2ljKCkKCmNvcih3ZXN0X2F0bF9zaGVsZl9hcmVhc1ssMzo1XSwgdXNlID0gImNvbXBsZXRlLm9icyIpCgpgYGAKCmBgYHtyIHBlcmNlbnQgc2hpZnQgd2VzdGVybiBhdGxhbnRpY30Kd2VzdF9hdGxfc2hlbGZfYXJlYXNbLCBwZXJjZW50X2NoYW5nZSA6PSAoYXJlYV9lcXVhbGFyZWFwcm9qLXNoaWZ0KGFyZWFfZXF1YWxhcmVhcHJvaiwgdHlwZSA9ICJsYWciKSkvc2hpZnQoYXJlYV9lcXVhbGFyZWFwcm9qLCB0eXBlID0gImxhZyIpXVssYXJlYV8xMDAwcyA6PSBhcmVhX2VxdWFsYXJlYXByb2ovMTAwMF0KCndlc3RfYXRsX3NoZWxmX2FyZWFzWywgY2hhbmdlX2Fib3ZlXzJmb2xkIDo9IGlmZWxzZSgocGVyY2VudF9jaGFuZ2U+PTEgJiBwZXJjZW50X2NoYW5nZTxJbmYpLCAxLCBpZmVsc2UocGVyY2VudF9jaGFuZ2U8PS0wLjUsIC0xLCAwKSldCgp3ZXN0X2F0bF9zaGVsZl9hcmVhc19oaWdobGlnaHQgPC0gd2VzdF9hdGxfc2hlbGZfYXJlYXNbY2hhbmdlX2Fib3ZlXzJmb2xkICE9IDAsXQoKd2VzdF9hdGxfc2hlbGZfYXJlYXNfc3RhdHMgPC0gdGFibGUod2VzdF9hdGxfc2hlbGZfYXJlYXNbLC4oY2hhbmdlX2Fib3ZlXzJmb2xkKV0pCmBgYAoKRWFzdGVybiBBdGxhbnRpYwoKZWFzdF9hdGxfc3BkZl9ub2J1Zl9tYXNrCgpgYGB7ciBzcGxpdCByYXN0ZXIgZm9yIGVhc3Rlcm4gYXRsYW50aWN9Cm5vcnRoX2V4dGVudCA8LSBjKHhtaW4oZWFzdF9hdGxfc3BkZl9ub2J1Zl9tYXNrXzFzKSwgeG1heChlYXN0X2F0bF9zcGRmX25vYnVmX21hc2tfMXMpLCAwLCB5bWF4KGVhc3RfYXRsX3NwZGZfbm9idWZfbWFza18xcykpCnNvdXRoX2V4dGVudCA8LSBjKHhtaW4oZWFzdF9hdGxfc3BkZl9ub2J1Zl9tYXNrXzFzKSwgeG1heChlYXN0X2F0bF9zcGRmX25vYnVmX21hc2tfMXMpLCB5bWluKGVhc3RfYXRsX3NwZGZfbm9idWZfbWFza18xcyksIDApCgojY3JvcCBlYXN0X2F0bCByYXN0ZXIgYWJvdmUgYW5kIGJlbG93IDAKZWFzdF9hdGxfc3BkZl9zaGlmdF9hZ2dfbm9ydGggPC0gY3JvcChlYXN0X2F0bF9zcGRmX25vYnVmX21hc2tfMXMsIGV4dGVudChub3J0aF9leHRlbnQpKQoKZWFzdF9hdGxfc3BkZl9zaGlmdF9hZ2dfc291dGggPC0gY3JvcChlYXN0X2F0bF9zcGRmX25vYnVmX21hc2tfMXMsIGV4dGVudChzb3V0aF9leHRlbnQpKQoKI3VuZm9ydHVuYXRlbHksIEkgdGhpbmsgSSBtYXkgaGF2ZSB0byBqdXN0IGRvIHRoaXMgbWFudWFsbHkgKHVnbHksIEkga25vdykKCiNhbGwgY2h1bmtzIGZvciBlYXN0IGF0bGFudGljCmVhc3RfYXRsX25vcnRoX2xhdGl0dWRlcyA8LSBzZXEoMCwgeW1heChlYXN0X2F0bF9zcGRmX25vYnVmX21hc2tfMXMpLCBieSA9IDEpCmVhc3RfYXRsX3NvdXRoX2xhdGl0dWRlcyA8LSBzZXEoMCwgeW1pbihlYXN0X2F0bF9zcGRmX25vYnVmX21hc2tfMXMpLCBieSA9IC0xKQoKI3NldHVwIGRhdGEgdGFibGUgdG8gcG9wdWxhdGUgaW4gbG9vcCwgc3VidHJhY3Rpbmcgb25lIHRvIGFsbG93IGZvciBiaW5zCmVhc3RfYXRsX3NoZWxmX2FyZWFzIDwtIGFzLmRhdGEudGFibGUobWF0cml4KG5yb3cgPSAobGVuZ3RoKGVhc3RfYXRsX25vcnRoX2xhdGl0dWRlcyktMStsZW5ndGgoZWFzdF9hdGxfc291dGhfbGF0aXR1ZGVzKS0xKSkpCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCmVhc3RfYXRsX3NoZWxmX2FyZWFzWywgbGF0aXR1ZGVfc3RhcnQgOj0gYXMubnVtZXJpYyhWMSldWywgbGF0aXR1ZGVfZW5kIDo9IGFzLm51bWVyaWMoVjEpXVssIGFyZWFfcmFzdGVyYXJlYSA6PSBhcy5udW1lcmljKFYxKV1bLCBhcmVhX2VxdWFsYXJlYXByb2ogOj0gYXMubnVtZXJpYyhWMSldWywgYXJlYV9yZ2Vvc19nQXJlYSA6PSBhcy5udW1lcmljKFYxKV1bLCBWMSA6PSBOVUxMXQoKI2xvb3AgZm9yIG5vcnRoCmZvciAoaSBpbiAxOihsZW5ndGgoZWFzdF9hdGxfbm9ydGhfbGF0aXR1ZGVzKS0xKSkgewogICNzZXR0aW5nIHVwIGV4dGVudCBmb3Igc2xpY2luZyBieSBtaW4gYW5kIG1heCBsb25naXR1ZGVzLCBhbmQgaSB0byBpKzEgbGF0aXR1ZGVzCiAgbm9ydGhfZXh0ZW50IDwtIGMoeG1pbihlYXN0X2F0bF9zcGRmX25vYnVmX21hc2tfMXMpLCB4bWF4KGVhc3RfYXRsX3NwZGZfbm9idWZfbWFza18xcyksIGVhc3RfYXRsX25vcnRoX2xhdGl0dWRlc1tpXSwgZWFzdF9hdGxfbm9ydGhfbGF0aXR1ZGVzW2krMV0pCiAgCiAgI2Nyb3AgcmFzdGVyIHNlZ2VtZW50IGJhc2VkIG9uIGJpbiBleHRlbnQKICBzZWdtZW50X25vcnRoIDwtIGNyb3AoZWFzdF9hdGxfc3BkZl9ub2J1Zl9tYXNrXzFzLCBleHRlbnQobm9ydGhfZXh0ZW50KSkKICAKICAjcG9wdWxhdGUgZGF0YSB0YWJsZSB3aXRoIGxhdGl0dWRpbmFsIGJpbgogIGVhc3RfYXRsX3NoZWxmX2FyZWFzW2ksICJsYXRpdHVkZV9zdGFydCJdIDwtIGVhc3RfYXRsX25vcnRoX2xhdGl0dWRlc1tpXQogIGVhc3RfYXRsX3NoZWxmX2FyZWFzW2ksICJsYXRpdHVkZV9lbmQiXSA8LSBlYXN0X2F0bF9ub3J0aF9sYXRpdHVkZXNbaSsxXQogIAogIGlmKGFsbChpcy5uYSh2YWx1ZXMoc2VnbWVudF9ub3J0aCkpKSkgeyAjaWYgdGhlcmUncyBubyBzaGVsZiBhcmVhIHdpdGhpbiBhIGJpbiwgYWxsIGFyZWEgPSAwCiAgICAKICBlYXN0X2F0bF9zaGVsZl9hcmVhc1tpLCAiYXJlYV9lcXVhbGFyZWFwcm9qIl0gPC0gMAogIGVhc3RfYXRsX3NoZWxmX2FyZWFzW2ksICJhcmVhX3Jhc3RlcmFyZWEiXSA8LSAwCiAgZWFzdF9hdGxfc2hlbGZfYXJlYXNbaSwgImFyZWFfcmdlb3NfZ0FyZWEiXSA8LSAwCgogIAogIHByaW50KGkpCiAgICAKICB9IGVsc2UgeyAjaWYgdGhlcmUgaXMgc2hlbGYgYXJlYSB3aXRoaW4gdGhlIGJpbiwgY2FsY3VsYXRlIGFyZWEgb2Ygc2xpY2UKICAKICAgICNyYXN0ZXIgYXJlYSBjYWxjdWxhdGlvbgogICAgICAjZ2V0IHNpemVzIG9mIGFsbCBjZWxscyBpbiByYXN0ZXIgW2ttMl0KICAgIGNlbGxfc2l6ZV9yYXN0ZXI8LWFyZWEoc2VnbWVudF9ub3J0aCwgbmEucm09VFJVRSwgd2VpZ2h0cz1GQUxTRSkKICAgIAogICAgI2RlbGV0ZSBOQXMgZnJvbSB2ZWN0b3Igb2YgYWxsIHJhc3RlciBjZWxscwogICAgY2VsbF9zaXplX3Jhc3RlcjwtY2VsbF9zaXplX3Jhc3RlclshaXMubmEoc2VnbWVudF9ub3J0aCldCiAgICAKICAgICNjb21wdXRlIGFyZWEgb2YgYWxsIGNlbGxzIGluIGdlb19yYXN0ZXIKICAgICNmdWxsIGFyZWEgICAgICAgICAgPC0gdG90YWwgIyBncmlkIGNlbGxzICAgICAqIG1lZGlhbiBjZWxsIGFyZWEgKHVzaW5nIG1lZGlhbiBjYXJlcyBsZXNzIGFib3V0IGV4dHJlbWUgdmFsdWVzKQogICAgc2VnbWVudF9hcmVhX3Jhc3RlciA8LSBsZW5ndGgoY2VsbF9zaXplX3Jhc3RlcikqbWVkaWFuKGNlbGxfc2l6ZV9yYXN0ZXIpICNpbiBrbV4yCiAgICAKICAjcG9wdWxhdGUgZGF0YSB0YWJsZSB3aXRoIHJhc3RlciBhcmVhCiAgZWFzdF9hdGxfc2hlbGZfYXJlYXNbaSwgImFyZWFfcmFzdGVyYXJlYSJdIDwtIHNlZ21lbnRfYXJlYV9yYXN0ZXIKICAgIAogICNjb252ZXJ0IHRvIHNwYXRpYWwgcG9seWdvbnMgdG8gY2hlY2sgYXJlYSBjYWxjdWxhdGlvbnMKICAgIAogICNjb252ZXJ0IHNlZ21lbnQgZnJvbSByYXN0ZXIgdG8gcG9seWdvbiwgZWFjaCBjZWxsIGZyb20gdGhlIHJhc3RlciBpcyBhbiBpbmRlcGVuZGVudCBwb2x5Z29uLCAoZGlzc29sdmUgbWVhbnMgYWxsIGNlbGxzIHdpdGggYSB2YWx1ZSBvZiAxIGFyZSBhIHNpbmdsZSBwb2x5Z29uIGlmIGNvbm5lY3RlZCkKICBzZWdtZW50X25vcnRoLnNwIDwtIHJhc3RlclRvUG9seWdvbnMoc2VnbWVudF9ub3J0aCwgZGlzc29sdmUgPSBUKQogIAogICMgIElmIHggaXMgYSBTcGF0aWFsUG9seWdvbnMqIG9iamVjdDogYXJlYSBvZiBlYWNoIHNwYXRpYWwgb2JqZWN0IGluIHNxdWFyZWQgbWV0ZXJzIGlmIHRoZSBDUlMgaXMgbG9uZ2l0dWRlL2xhdGl0dWRlLCBvciBpbiBzcXVhcmVkIG1hcCB1bml0cyAodHlwaWNhbGx5IG1ldGVyKQogIAogICAgI3Byb2plY3QgdG8gZXF1YWwgZWFydGggYXJlYSBwcm9qZWN0aW9uCiAgc2VnbWVudF9ub3J0aC5zcC5FQSA8LSBzcFRyYW5zZm9ybShzZWdtZW50X25vcnRoLnNwLCBDUlNvYmogPSBlcXVhbGFyZWFwcm9qZWN0aW9uKQoKICAjY2FsY3VsYXRlIGFyZWEgb2YgdGhlIHNwYXRpYWwgb2JqZWN0IGluIG1eMgogICAgcG9seWdvbl9zaXplLnNwIDwtIGFyZWEoc2VnbWVudF9ub3J0aC5zcC5FQSkKCiAgICAjY29udmVydCBmcm9tIG1eMiB0byBrbV4yCiAgICBzZWdtZW50X2FyZWFfZXF1YWxhcmVhIDwtIHBvbHlnb25fc2l6ZS5zcC8xZTYKCiAgICAjcG9wdWxhdGUgZGF0YSB0YWJsZSB3aXRoIHBvbHlnb24gYXJlYSB1c2luZyByYXN0ZXIgY2FsY3VsYXRpb24KICBlYXN0X2F0bF9zaGVsZl9hcmVhc1tpLCAiYXJlYV9lcXVhbGFyZWFwcm9qIl0gPC0gc2VnbWVudF9hcmVhX2VxdWFsYXJlYQogIAogICNhbmQgdGhlbiBwbGFpbiBhbmQgc2ltcGxlIGFsc28gdXNpbmcgcmdlb3M6OmdBcmVhCiAgCiAgYXJlYV9yZ2Vvc19nQXJlYSA8LSBnQXJlYShzZWdtZW50X25vcnRoLnNwLkVBKS8xZTYKICAKICAjcG9wdWxhdGUgZGF0YSB0YWJsZSB3aXRoIHBvbHlnb24gYXJlYSB1c2luZyByZWdlb3MgY2FsY3VsYXRpb24KICBlYXN0X2F0bF9zaGVsZl9hcmVhc1tpLCAiYXJlYV9yZ2Vvc19nQXJlYSJdIDwtICAgYXJlYV9yZ2Vvc19nQXJlYQogIAogIHByaW50KGkpCiAgfSAKfQoKI2xvb3AgZm9yIHNvdXRoCmZvciAoaSBpbiAxOihsZW5ndGgoZWFzdF9hdGxfc291dGhfbGF0aXR1ZGVzKS0xKSkgewogIHNvdXRoX2V4dGVudCA8LSBjKHhtaW4oZWFzdF9hdGxfc3BkZl9ub2J1Zl9tYXNrXzFzKSwgeG1heChlYXN0X2F0bF9zcGRmX25vYnVmX21hc2tfMXMpLCBlYXN0X2F0bF9zb3V0aF9sYXRpdHVkZXNbaSsxXSwgZWFzdF9hdGxfc291dGhfbGF0aXR1ZGVzW2ldKSAjb3JkZXI9IHhtaW4sIHhtYXgsIHltaW4sIHltYXgpCiAgCiAgI3Jhc3RlciBzZWdtZW50CiAgc2VnbWVudF9zb3V0aCA8LSBjcm9wKGVhc3RfYXRsX3NwZGZfbm9idWZfbWFza18xcywgZXh0ZW50KHNvdXRoX2V4dGVudCkpCiAgCiAgI2FkZCBsYXRpdHVkZSBiaW4gaW5mbyB0byBkYXRhIHRhYmxlCiAgICBlYXN0X2F0bF9zaGVsZl9hcmVhc1tpKyhsZW5ndGgoZWFzdF9hdGxfbm9ydGhfbGF0aXR1ZGVzKS0xKSwgImxhdGl0dWRlX3N0YXJ0Il0gPC0gZWFzdF9hdGxfc291dGhfbGF0aXR1ZGVzW2ldCiAgZWFzdF9hdGxfc2hlbGZfYXJlYXNbaSsobGVuZ3RoKGVhc3RfYXRsX25vcnRoX2xhdGl0dWRlcyktMSksICJsYXRpdHVkZV9lbmQiXSA8LSBlYXN0X2F0bF9zb3V0aF9sYXRpdHVkZXNbaSsxXQogIAogIAogIGlmKGFsbChpcy5uYSh2YWx1ZXMoc2VnbWVudF9zb3V0aCkpKSkgeyAjaWYgdGhlcmUncyBubyBzaGVsZiBhcmVhIHdpdGhpbiBhIGJpbiwgbWVhbmluZyB0aGVyZSdzIG5vIHNoZWxmIGFyZWEgYXQgdGhhdCBsYXRpdHVkZQoKICBlYXN0X2F0bF9zaGVsZl9hcmVhc1tpKyhsZW5ndGgoZWFzdF9hdGxfbm9ydGhfbGF0aXR1ZGVzKS0xKSwgImFyZWFfZXF1YWxhcmVhcHJvaiJdIDwtIDAKICBlYXN0X2F0bF9zaGVsZl9hcmVhc1tpKyhsZW5ndGgoZWFzdF9hdGxfbm9ydGhfbGF0aXR1ZGVzKS0xKSwgImFyZWFfcmFzdGVyYXJlYSJdIDwtIDAKICAgIGVhc3RfYXRsX3NoZWxmX2FyZWFzW2krKGxlbmd0aChlYXN0X2F0bF9ub3J0aF9sYXRpdHVkZXMpLTEpLCAiYXJlYV9yZ2Vvc19nQXJlYSJdIDwtIDAKICAKICBwcmludChpKQogICAgCiAgfSBlbHNlIHsKICAKICAgICNyYXN0ZXIgYXJlYSBjYWxjdWxhdGlvbgogICAgICAjZ2V0IHNpemVzIG9mIGFsbCBjZWxscyBpbiByYXN0ZXIgW2ttMl0KICAgIGNlbGxfc2l6ZV9yYXN0ZXI8LWFyZWEoc2VnbWVudF9zb3V0aCwgbmEucm09VFJVRSwgd2VpZ2h0cz1GQUxTRSkKICAgIAogICAgI2RlbGV0ZSBOQXMgZnJvbSB2ZWN0b3Igb2YgYWxsIHJhc3RlciBjZWxscwogICAgY2VsbF9zaXplX3Jhc3RlcjwtY2VsbF9zaXplX3Jhc3RlclshaXMubmEoc2VnbWVudF9zb3V0aCldCiAgICAjY29tcHV0ZSBhcmVhIG9mIGFsbCBjZWxscyBpbiBnZW9fcmFzdGVyCiAgICAjZnVsbCBhcmVhICAgICAgICAgIDwtIHRvdGFsICMgZ3JpZCBjZWxscyAgICAgKiBtZWRpYW4gY2VsbCBhcmVhICh1c2luZyBtZWRpYW4gY2FyZXMgbGVzcyBhYm91dCBleHRyZW1lIHZhbHVlcykKICAgIHNlZ21lbnRfYXJlYV9yYXN0ZXIgPC0gbGVuZ3RoKGNlbGxfc2l6ZV9yYXN0ZXIpKm1lZGlhbihjZWxsX3NpemVfcmFzdGVyKQogICAgCiAgI3BvcHVsYXRlIGRhdGEgdGFibGUgd2l0aCByYXN0ZXIgYXJlYQogIGVhc3RfYXRsX3NoZWxmX2FyZWFzW2krKGxlbmd0aChlYXN0X2F0bF9ub3J0aF9sYXRpdHVkZXMpLTEpLCAiYXJlYV9yYXN0ZXJhcmVhIl0gPC0gc2VnbWVudF9hcmVhX3Jhc3RlcgogICAgCiAgCiAgI2NvbnZlcnQgdG8gc3BhdGlhbCBwb2x5Z29ucyB0byBjaGVjayBhcmVhIGNhbGN1bGF0aW9ucwogICAgCiAgI2NvbnZlcnQgc2VnbWVudCBmcm9tIHJhc3RlciB0byBwb2x5Z29uLCBlYWNoIGNlbGwgZnJvbSB0aGUgcmFzdGVyIGlzIGFuIGluZGVwZW5kZW50IHBvbHlnb24sIChkaXNzb2x2ZSBtZWFucyBhbGwgY2VsbHMgd2l0aCBhIHZhbHVlIG9mIDEgYXJlIGEgc2luZ2xlIHBvbHlnb24gaWYgY29ubmVjdGVkKQogIHNlZ21lbnRfc291dGguc3AgPC0gcmFzdGVyVG9Qb2x5Z29ucyhzZWdtZW50X3NvdXRoLCBkaXNzb2x2ZSA9IFQpCiAgCiAgIyAgSWYgeCBpcyBhIFNwYXRpYWxQb2x5Z29ucyogb2JqZWN0OiBhcmVhIG9mIGVhY2ggc3BhdGlhbCBvYmplY3QgaW4gc3F1YXJlZCBtZXRlcnMgaWYgdGhlIENSUyBpcyBsb25naXR1ZGUvbGF0aXR1ZGUsIG9yIGluIHNxdWFyZWQgbWFwIHVuaXRzICh0eXBpY2FsbHkgbWV0ZXIpCiAgCiAgICAjcHJvamVjdCB0byBlcXVhbCBlYXJ0aCBhcmVhIHByb2plY3Rpb24KICBzZWdtZW50X3NvdXRoLnNwLkVBIDwtIHNwVHJhbnNmb3JtKHNlZ21lbnRfc291dGguc3AsIENSU29iaiA9IGVxdWFsYXJlYXByb2plY3Rpb24pCgogICNjYWxjdWxhdGUgYXJlYSBvZiB0aGUgc3BhdGlhbCBvYmplY3QgaW4gbV4yCiAgICBwb2x5Z29uX3NpemUuc3AgPC0gYXJlYShzZWdtZW50X3NvdXRoLnNwLkVBKQoKICAgICNjb252ZXJ0IGZyb20gbV4yIHRvIGttXjIKICAgIHNlZ21lbnRfYXJlYV9lcXVhbGFyZWEgPC0gcG9seWdvbl9zaXplLnNwLzFlNgoKICAgICNwb3B1bGF0ZSBkYXRhIHRhYmxlIHdpdGggYXJlYSBvZiBwb2x5Z29uIGZyb20gcmFzdGVyOjphcmVhIGZ1bmN0aW9uCiAgZWFzdF9hdGxfc2hlbGZfYXJlYXNbaSsobGVuZ3RoKGVhc3RfYXRsX25vcnRoX2xhdGl0dWRlcyktMSksICJhcmVhX2VxdWFsYXJlYXByb2oiXSA8LSBzZWdtZW50X2FyZWFfZXF1YWxhcmVhCiAgCiAgI2FuZCB0aGVuIHBsYWluIGFuZCBzaW1wbGUgYWxzbyB1c2luZyByZ2Vvczo6Z0FyZWEKICAKICBhcmVhX3JnZW9zX2dBcmVhIDwtIGdBcmVhKHNlZ21lbnRfc291dGguc3AuRUEpLzFlNgogIAogICNwb3B1bGF0ZSBkYXRhIHRhYmxlIGZyb20gcmdlb3MgYXJlYSBjYWxjdWxhdGlvbiBmb3IgcHJvamVjdGVkIHBvbHlnb24KICBlYXN0X2F0bF9zaGVsZl9hcmVhc1tpKyhsZW5ndGgoZWFzdF9hdGxfbm9ydGhfbGF0aXR1ZGVzKS0xKSwgImFyZWFfcmdlb3NfZ0FyZWEiXSA8LSAgIGFyZWFfcmdlb3NfZ0FyZWEKICAKICBwcmludChpKQogIH0gCn0KCiNjb21wYXJlIHJhc3RlcjphcmVhIGNhbGN1bGF0aW9uLCB0byBlcXVhbCBhcmVhIHN0aWxsIHVzaW5nIHJhc3Rlcjo6YXJlYSBmdW5jdGlvbiwgdG8gcmdlb3M6OmdBcmVhIGZ1bmN0aW9uIGZvciBwb2x5Z29ucwoKZ2dwbG90KGRhdGEgPSBlYXN0X2F0bF9zaGVsZl9hcmVhcykgKwogIGdlb21fcG9pbnQoYWVzKHggPSBsYXRpdHVkZV9zdGFydCwgeSA9IGFyZWFfcmdlb3NfZ0FyZWEpLCBjb2xvciA9ICJwdXJwbGUiLCBzaXplID0gMC41KSArCiAgZ2VvbV9wb2ludChhZXMoeCA9IGxhdGl0dWRlX3N0YXJ0LCB5ID0gYXJlYV9yYXN0ZXJhcmVhKSwgY29sb3IgPSAiZGFya2dyZWVuIiwgc2l6ZSA9IDAuNSkgKwogIGdlb21fcG9pbnQoYWVzKHggPSBsYXRpdHVkZV9zdGFydCwgeSA9IGFyZWFfZXF1YWxhcmVhcHJvaiksIGNvbG9yID0gInJlZCIsIHNpemUgPSAwLjUpICsKICBsYWJzKHggPSAiTGF0aXR1ZGUiLCB5ID0gIkFyZWEga21eMiIpICsKICB0aGVtZV9jbGFzc2ljKCkKCmNvcihlYXN0X2F0bF9zaGVsZl9hcmVhc1ssMzo1XSwgdXNlID0gImNvbXBsZXRlLm9icyIpCgpgYGAKCmBgYHtyIHBlcmNlbnQgc2hpZnQgZWFzdGVybiBhdGxhbnRpY30KZWFzdF9hdGxfc2hlbGZfYXJlYXNbLCBwZXJjZW50X2NoYW5nZSA6PSAoYXJlYV9lcXVhbGFyZWFwcm9qLXNoaWZ0KGFyZWFfZXF1YWxhcmVhcHJvaiwgdHlwZSA9ICJsYWciKSkvc2hpZnQoYXJlYV9lcXVhbGFyZWFwcm9qLCB0eXBlID0gImxhZyIpXVssYXJlYV8xMDAwcyA6PSBhcmVhX2VxdWFsYXJlYXByb2ovMTAwMF0KCmVhc3RfYXRsX3NoZWxmX2FyZWFzWywgY2hhbmdlX2Fib3ZlXzJmb2xkIDo9IGlmZWxzZSgocGVyY2VudF9jaGFuZ2U+PTEgJiBwZXJjZW50X2NoYW5nZTxJbmYpLCAxLCBpZmVsc2UocGVyY2VudF9jaGFuZ2U8PS0wLjUsIC0xLCAwKSldCgplYXN0X2F0bF9zaGVsZl9hcmVhc19oaWdobGlnaHQgPC0gZWFzdF9hdGxfc2hlbGZfYXJlYXNbY2hhbmdlX2Fib3ZlXzJmb2xkICE9IDAsXQoKZWFzdF9hdGxfc2hlbGZfYXJlYXNfc3RhdHMgPC0gdGFibGUoZWFzdF9hdGxfc2hlbGZfYXJlYXNbLC4oY2hhbmdlX2Fib3ZlXzJmb2xkKV0pCmBgYAoKV2VzdGVybiBJbmRpYW4KCndlc3RfaW5kX3NwZGZfbWFzawoKYGBge3Igc3BsaXQgcmFzdGVyIGZvciB3ZXN0ZXJuIGluZGlhbn0Kbm9ydGhfZXh0ZW50IDwtIGMoeG1pbih3ZXN0X2luZF9zcGRmX21hc2tfMXMpLCB4bWF4KHdlc3RfaW5kX3NwZGZfbWFza18xcyksIDAsIHltYXgod2VzdF9pbmRfc3BkZl9tYXNrXzFzKSkKc291dGhfZXh0ZW50IDwtIGMoeG1pbih3ZXN0X2luZF9zcGRmX21hc2tfMXMpLCB4bWF4KHdlc3RfaW5kX3NwZGZfbWFza18xcyksIHltaW4od2VzdF9pbmRfc3BkZl9tYXNrXzFzKSwgMCkKCiNjcm9wIHdlc3RfaW5kIHJhc3RlciBhYm92ZSBhbmQgYmVsb3cgMAp3ZXN0X2luZF9zcGRmX3NoaWZ0X2FnZ19ub3J0aCA8LSBjcm9wKHdlc3RfaW5kX3NwZGZfbWFza18xcywgZXh0ZW50KG5vcnRoX2V4dGVudCkpCgp3ZXN0X2luZF9zcGRmX3NoaWZ0X2FnZ19zb3V0aCA8LSBjcm9wKHdlc3RfaW5kX3NwZGZfbWFza18xcywgZXh0ZW50KHNvdXRoX2V4dGVudCkpCgojdW5mb3J0dW5hdGVseSwgSSB0aGluayBJIG1heSBoYXZlIHRvIGp1c3QgZG8gdGhpcyBtYW51YWxseSAodWdseSwgSSBrbm93KQoKI2FsbCBjaHVua3MgZm9yIHdlc3QgaW5kaWFuCndlc3RfaW5kX25vcnRoX2xhdGl0dWRlcyA8LSBzZXEoMCwgeW1heCh3ZXN0X2luZF9zcGRmX21hc2tfMXMpLCBieSA9IDEpCndlc3RfaW5kX3NvdXRoX2xhdGl0dWRlcyA8LSBzZXEoMCwgeW1pbih3ZXN0X2luZF9zcGRmX21hc2tfMXMpLCBieSA9IC0xKQoKI3NldHVwIGRhdGEgdGFibGUgdG8gcG9wdWxhdGUgaW4gbG9vcCwgc3VidHJhY3Rpbmcgb25lIHRvIGFsbG93IGZvciBiaW5zCndlc3RfaW5kX3NoZWxmX2FyZWFzIDwtIGFzLmRhdGEudGFibGUobWF0cml4KG5yb3cgPSAobGVuZ3RoKHdlc3RfaW5kX25vcnRoX2xhdGl0dWRlcyktMStsZW5ndGgod2VzdF9pbmRfc291dGhfbGF0aXR1ZGVzKS0xKSkpCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCndlc3RfaW5kX3NoZWxmX2FyZWFzWywgbGF0aXR1ZGVfc3RhcnQgOj0gYXMubnVtZXJpYyhWMSldWywgbGF0aXR1ZGVfZW5kIDo9IGFzLm51bWVyaWMoVjEpXVssIGFyZWFfcmFzdGVyYXJlYSA6PSBhcy5udW1lcmljKFYxKV1bLCBhcmVhX2VxdWFsYXJlYXByb2ogOj0gYXMubnVtZXJpYyhWMSldWywgYXJlYV9yZ2Vvc19nQXJlYSA6PSBhcy5udW1lcmljKFYxKV1bLCBWMSA6PSBOVUxMXQoKI2xvb3AgZm9yIG5vcnRoCmZvciAoaSBpbiAxOihsZW5ndGgod2VzdF9pbmRfbm9ydGhfbGF0aXR1ZGVzKS0xKSkgewogICNzZXR0aW5nIHVwIGV4dGVudCBmb3Igc2xpY2luZyBieSBtaW4gYW5kIG1heCBsb25naXR1ZGVzLCBhbmQgaSB0byBpKzEgbGF0aXR1ZGVzCiAgbm9ydGhfZXh0ZW50IDwtIGMoeG1pbih3ZXN0X2luZF9zcGRmX21hc2tfMXMpLCB4bWF4KHdlc3RfaW5kX3NwZGZfbWFza18xcyksIHdlc3RfaW5kX25vcnRoX2xhdGl0dWRlc1tpXSwgd2VzdF9pbmRfbm9ydGhfbGF0aXR1ZGVzW2krMV0pCiAgCiAgI2Nyb3AgcmFzdGVyIHNlZ2VtZW50IGJhc2VkIG9uIGJpbiBleHRlbnQKICBzZWdtZW50X25vcnRoIDwtIGNyb3Aod2VzdF9pbmRfc3BkZl9tYXNrXzFzLCBleHRlbnQobm9ydGhfZXh0ZW50KSkKICAKICAjcG9wdWxhdGUgZGF0YSB0YWJsZSB3aXRoIGxhdGl0dWRpbmFsIGJpbgogIHdlc3RfaW5kX3NoZWxmX2FyZWFzW2ksICJsYXRpdHVkZV9zdGFydCJdIDwtIHdlc3RfaW5kX25vcnRoX2xhdGl0dWRlc1tpXQogIHdlc3RfaW5kX3NoZWxmX2FyZWFzW2ksICJsYXRpdHVkZV9lbmQiXSA8LSB3ZXN0X2luZF9ub3J0aF9sYXRpdHVkZXNbaSsxXQogIAogIGlmKGFsbChpcy5uYSh2YWx1ZXMoc2VnbWVudF9ub3J0aCkpKSkgeyAjaWYgdGhlcmUncyBubyBzaGVsZiBhcmVhIHdpdGhpbiBhIGJpbiwgYWxsIGFyZWEgPSAwCiAgICAKICB3ZXN0X2luZF9zaGVsZl9hcmVhc1tpLCAiYXJlYV9lcXVhbGFyZWFwcm9qIl0gPC0gMAogIHdlc3RfaW5kX3NoZWxmX2FyZWFzW2ksICJhcmVhX3Jhc3RlcmFyZWEiXSA8LSAwCiAgd2VzdF9pbmRfc2hlbGZfYXJlYXNbaSwgImFyZWFfcmdlb3NfZ0FyZWEiXSA8LSAwCgogIAogIHByaW50KGkpCiAgICAKICB9IGVsc2UgeyAjaWYgdGhlcmUgaXMgc2hlbGYgYXJlYSB3aXRoaW4gdGhlIGJpbiwgY2FsY3VsYXRlIGFyZWEgb2Ygc2xpY2UKICAKICAgICNyYXN0ZXIgYXJlYSBjYWxjdWxhdGlvbgogICAgICAjZ2V0IHNpemVzIG9mIGFsbCBjZWxscyBpbiByYXN0ZXIgW2ttMl0KICAgIGNlbGxfc2l6ZV9yYXN0ZXI8LWFyZWEoc2VnbWVudF9ub3J0aCwgbmEucm09VFJVRSwgd2VpZ2h0cz1GQUxTRSkKICAgIAogICAgI2RlbGV0ZSBOQXMgZnJvbSB2ZWN0b3Igb2YgYWxsIHJhc3RlciBjZWxscwogICAgY2VsbF9zaXplX3Jhc3RlcjwtY2VsbF9zaXplX3Jhc3RlclshaXMubmEoc2VnbWVudF9ub3J0aCldCiAgICAKICAgICNjb21wdXRlIGFyZWEgb2YgYWxsIGNlbGxzIGluIGdlb19yYXN0ZXIKICAgICNmdWxsIGFyZWEgICAgICAgICAgPC0gdG90YWwgIyBncmlkIGNlbGxzICAgICAqIG1lZGlhbiBjZWxsIGFyZWEgKHVzaW5nIG1lZGlhbiBjYXJlcyBsZXNzIGFib3V0IGV4dHJlbWUgdmFsdWVzKQogICAgc2VnbWVudF9hcmVhX3Jhc3RlciA8LSBsZW5ndGgoY2VsbF9zaXplX3Jhc3RlcikqbWVkaWFuKGNlbGxfc2l6ZV9yYXN0ZXIpICNpbiBrbV4yCiAgICAKICAjcG9wdWxhdGUgZGF0YSB0YWJsZSB3aXRoIHJhc3RlciBhcmVhCiAgd2VzdF9pbmRfc2hlbGZfYXJlYXNbaSwgImFyZWFfcmFzdGVyYXJlYSJdIDwtIHNlZ21lbnRfYXJlYV9yYXN0ZXIKICAgIAogICNjb252ZXJ0IHRvIHNwYXRpYWwgcG9seWdvbnMgdG8gY2hlY2sgYXJlYSBjYWxjdWxhdGlvbnMKICAgIAogICNjb252ZXJ0IHNlZ21lbnQgZnJvbSByYXN0ZXIgdG8gcG9seWdvbiwgZWFjaCBjZWxsIGZyb20gdGhlIHJhc3RlciBpcyBhbiBpbmRlcGVuZGVudCBwb2x5Z29uLCAoZGlzc29sdmUgbWVhbnMgYWxsIGNlbGxzIHdpdGggYSB2YWx1ZSBvZiAxIGFyZSBhIHNpbmdsZSBwb2x5Z29uIGlmIGNvbm5lY3RlZCkKICBzZWdtZW50X25vcnRoLnNwIDwtIHJhc3RlclRvUG9seWdvbnMoc2VnbWVudF9ub3J0aCwgZGlzc29sdmUgPSBUKQogIAogICMgIElmIHggaXMgYSBTcGF0aWFsUG9seWdvbnMqIG9iamVjdDogYXJlYSBvZiBlYWNoIHNwYXRpYWwgb2JqZWN0IGluIHNxdWFyZWQgbWV0ZXJzIGlmIHRoZSBDUlMgaXMgbG9uZ2l0dWRlL2xhdGl0dWRlLCBvciBpbiBzcXVhcmVkIG1hcCB1bml0cyAodHlwaWNhbGx5IG1ldGVyKQogIAogICAgI3Byb2plY3QgdG8gZXF1YWwgZWFydGggYXJlYSBwcm9qZWN0aW9uCiAgc2VnbWVudF9ub3J0aC5zcC5FQSA8LSBzcFRyYW5zZm9ybShzZWdtZW50X25vcnRoLnNwLCBDUlNvYmogPSBlcXVhbGFyZWFwcm9qZWN0aW9uKQoKICAjY2FsY3VsYXRlIGFyZWEgb2YgdGhlIHNwYXRpYWwgb2JqZWN0IGluIG1eMgogICAgcG9seWdvbl9zaXplLnNwIDwtIGFyZWEoc2VnbWVudF9ub3J0aC5zcC5FQSkKCiAgICAjY29udmVydCBmcm9tIG1eMiB0byBrbV4yCiAgICBzZWdtZW50X2FyZWFfZXF1YWxhcmVhIDwtIHBvbHlnb25fc2l6ZS5zcC8xZTYKCiAgICAjcG9wdWxhdGUgZGF0YSB0YWJsZSB3aXRoIHBvbHlnb24gYXJlYSB1c2luZyByYXN0ZXIgY2FsY3VsYXRpb24KICB3ZXN0X2luZF9zaGVsZl9hcmVhc1tpLCAiYXJlYV9lcXVhbGFyZWFwcm9qIl0gPC0gc2VnbWVudF9hcmVhX2VxdWFsYXJlYQogIAogICNhbmQgdGhlbiBwbGFpbiBhbmQgc2ltcGxlIGFsc28gdXNpbmcgcmdlb3M6OmdBcmVhCiAgCiAgYXJlYV9yZ2Vvc19nQXJlYSA8LSBnQXJlYShzZWdtZW50X25vcnRoLnNwLkVBKS8xZTYKICAKICAjcG9wdWxhdGUgZGF0YSB0YWJsZSB3aXRoIHBvbHlnb24gYXJlYSB1c2luZyByZWdlb3MgY2FsY3VsYXRpb24KICB3ZXN0X2luZF9zaGVsZl9hcmVhc1tpLCAiYXJlYV9yZ2Vvc19nQXJlYSJdIDwtICAgYXJlYV9yZ2Vvc19nQXJlYQogIAogIHByaW50KGkpCiAgfSAKfQoKI2xvb3AgZm9yIHNvdXRoCmZvciAoaSBpbiAxOihsZW5ndGgod2VzdF9pbmRfc291dGhfbGF0aXR1ZGVzKS0xKSkgewogIHNvdXRoX2V4dGVudCA8LSBjKHhtaW4od2VzdF9pbmRfc3BkZl9tYXNrXzFzKSwgeG1heCh3ZXN0X2luZF9zcGRmX21hc2tfMXMpLCB3ZXN0X2luZF9zb3V0aF9sYXRpdHVkZXNbaSsxXSwgd2VzdF9pbmRfc291dGhfbGF0aXR1ZGVzW2ldKSAjb3JkZXI9IHhtaW4sIHhtYXgsIHltaW4sIHltYXgpCiAgCiAgI3Jhc3RlciBzZWdtZW50CiAgc2VnbWVudF9zb3V0aCA8LSBjcm9wKHdlc3RfaW5kX3NwZGZfbWFza18xcywgZXh0ZW50KHNvdXRoX2V4dGVudCkpCiAgCiAgI2FkZCBsYXRpdHVkZSBiaW4gaW5mbyB0byBkYXRhIHRhYmxlCiAgICB3ZXN0X2luZF9zaGVsZl9hcmVhc1tpKyhsZW5ndGgod2VzdF9pbmRfbm9ydGhfbGF0aXR1ZGVzKS0xKSwgImxhdGl0dWRlX3N0YXJ0Il0gPC0gd2VzdF9pbmRfc291dGhfbGF0aXR1ZGVzW2ldCiAgd2VzdF9pbmRfc2hlbGZfYXJlYXNbaSsobGVuZ3RoKHdlc3RfaW5kX25vcnRoX2xhdGl0dWRlcyktMSksICJsYXRpdHVkZV9lbmQiXSA8LSB3ZXN0X2luZF9zb3V0aF9sYXRpdHVkZXNbaSsxXQogIAogIAogIGlmKGFsbChpcy5uYSh2YWx1ZXMoc2VnbWVudF9zb3V0aCkpKSkgeyAjaWYgdGhlcmUncyBubyBzaGVsZiBhcmVhIHdpdGhpbiBhIGJpbiwgbWVhbmluZyB0aGVyZSdzIG5vIHNoZWxmIGFyZWEgYXQgdGhhdCBsYXRpdHVkZQoKICB3ZXN0X2luZF9zaGVsZl9hcmVhc1tpKyhsZW5ndGgod2VzdF9pbmRfbm9ydGhfbGF0aXR1ZGVzKS0xKSwgImFyZWFfZXF1YWxhcmVhcHJvaiJdIDwtIDAKICB3ZXN0X2luZF9zaGVsZl9hcmVhc1tpKyhsZW5ndGgod2VzdF9pbmRfbm9ydGhfbGF0aXR1ZGVzKS0xKSwgImFyZWFfcmFzdGVyYXJlYSJdIDwtIDAKICAgIHdlc3RfaW5kX3NoZWxmX2FyZWFzW2krKGxlbmd0aCh3ZXN0X2luZF9ub3J0aF9sYXRpdHVkZXMpLTEpLCAiYXJlYV9yZ2Vvc19nQXJlYSJdIDwtIDAKICAKICBwcmludChpKQogICAgCiAgfSBlbHNlIHsKICAKICAgICNyYXN0ZXIgYXJlYSBjYWxjdWxhdGlvbgogICAgICAjZ2V0IHNpemVzIG9mIGFsbCBjZWxscyBpbiByYXN0ZXIgW2ttMl0KICAgIGNlbGxfc2l6ZV9yYXN0ZXI8LWFyZWEoc2VnbWVudF9zb3V0aCwgbmEucm09VFJVRSwgd2VpZ2h0cz1GQUxTRSkKICAgIAogICAgI2RlbGV0ZSBOQXMgZnJvbSB2ZWN0b3Igb2YgYWxsIHJhc3RlciBjZWxscwogICAgY2VsbF9zaXplX3Jhc3RlcjwtY2VsbF9zaXplX3Jhc3RlclshaXMubmEoc2VnbWVudF9zb3V0aCldCiAgICAjY29tcHV0ZSBhcmVhIG9mIGFsbCBjZWxscyBpbiBnZW9fcmFzdGVyCiAgICAjZnVsbCBhcmVhICAgICAgICAgIDwtIHRvdGFsICMgZ3JpZCBjZWxscyAgICAgKiBtZWRpYW4gY2VsbCBhcmVhICh1c2luZyBtZWRpYW4gY2FyZXMgbGVzcyBhYm91dCBleHRyZW1lIHZhbHVlcykKICAgIHNlZ21lbnRfYXJlYV9yYXN0ZXIgPC0gbGVuZ3RoKGNlbGxfc2l6ZV9yYXN0ZXIpKm1lZGlhbihjZWxsX3NpemVfcmFzdGVyKQogICAgCiAgI3BvcHVsYXRlIGRhdGEgdGFibGUgd2l0aCByYXN0ZXIgYXJlYQogIHdlc3RfaW5kX3NoZWxmX2FyZWFzW2krKGxlbmd0aCh3ZXN0X2luZF9ub3J0aF9sYXRpdHVkZXMpLTEpLCAiYXJlYV9yYXN0ZXJhcmVhIl0gPC0gc2VnbWVudF9hcmVhX3Jhc3RlcgogICAgCiAgCiAgI2NvbnZlcnQgdG8gc3BhdGlhbCBwb2x5Z29ucyB0byBjaGVjayBhcmVhIGNhbGN1bGF0aW9ucwogICAgCiAgI2NvbnZlcnQgc2VnbWVudCBmcm9tIHJhc3RlciB0byBwb2x5Z29uLCBlYWNoIGNlbGwgZnJvbSB0aGUgcmFzdGVyIGlzIGFuIGluZGVwZW5kZW50IHBvbHlnb24sIChkaXNzb2x2ZSBtZWFucyBhbGwgY2VsbHMgd2l0aCBhIHZhbHVlIG9mIDEgYXJlIGEgc2luZ2xlIHBvbHlnb24gaWYgY29ubmVjdGVkKQogIHNlZ21lbnRfc291dGguc3AgPC0gcmFzdGVyVG9Qb2x5Z29ucyhzZWdtZW50X3NvdXRoLCBkaXNzb2x2ZSA9IFQpCiAgCiAgIyAgSWYgeCBpcyBhIFNwYXRpYWxQb2x5Z29ucyogb2JqZWN0OiBhcmVhIG9mIGVhY2ggc3BhdGlhbCBvYmplY3QgaW4gc3F1YXJlZCBtZXRlcnMgaWYgdGhlIENSUyBpcyBsb25naXR1ZGUvbGF0aXR1ZGUsIG9yIGluIHNxdWFyZWQgbWFwIHVuaXRzICh0eXBpY2FsbHkgbWV0ZXIpCiAgCiAgICAjcHJvamVjdCB0byBlcXVhbCBlYXJ0aCBhcmVhIHByb2plY3Rpb24KICBzZWdtZW50X3NvdXRoLnNwLkVBIDwtIHNwVHJhbnNmb3JtKHNlZ21lbnRfc291dGguc3AsIENSU29iaiA9IGVxdWFsYXJlYXByb2plY3Rpb24pCgogICNjYWxjdWxhdGUgYXJlYSBvZiB0aGUgc3BhdGlhbCBvYmplY3QgaW4gbV4yCiAgICBwb2x5Z29uX3NpemUuc3AgPC0gYXJlYShzZWdtZW50X3NvdXRoLnNwLkVBKQoKICAgICNjb252ZXJ0IGZyb20gbV4yIHRvIGttXjIKICAgIHNlZ21lbnRfYXJlYV9lcXVhbGFyZWEgPC0gcG9seWdvbl9zaXplLnNwLzFlNgoKICAgICNwb3B1bGF0ZSBkYXRhIHRhYmxlIHdpdGggYXJlYSBvZiBwb2x5Z29uIGZyb20gcmFzdGVyOjphcmVhIGZ1bmN0aW9uCiAgd2VzdF9pbmRfc2hlbGZfYXJlYXNbaSsobGVuZ3RoKHdlc3RfaW5kX25vcnRoX2xhdGl0dWRlcyktMSksICJhcmVhX2VxdWFsYXJlYXByb2oiXSA8LSBzZWdtZW50X2FyZWFfZXF1YWxhcmVhCiAgCiAgI2FuZCB0aGVuIHBsYWluIGFuZCBzaW1wbGUgYWxzbyB1c2luZyByZ2Vvczo6Z0FyZWEKICAKICBhcmVhX3JnZW9zX2dBcmVhIDwtIGdBcmVhKHNlZ21lbnRfc291dGguc3AuRUEpLzFlNgogIAogICNwb3B1bGF0ZSBkYXRhIHRhYmxlIGZyb20gcmdlb3MgYXJlYSBjYWxjdWxhdGlvbiBmb3IgcHJvamVjdGVkIHBvbHlnb24KICB3ZXN0X2luZF9zaGVsZl9hcmVhc1tpKyhsZW5ndGgod2VzdF9pbmRfbm9ydGhfbGF0aXR1ZGVzKS0xKSwgImFyZWFfcmdlb3NfZ0FyZWEiXSA8LSAgIGFyZWFfcmdlb3NfZ0FyZWEKICAKICBwcmludChpKQogIH0gCn0KCiNjb21wYXJlIHJhc3RlcjphcmVhIGNhbGN1bGF0aW9uLCB0byBlcXVhbCBhcmVhIHN0aWxsIHVzaW5nIHJhc3Rlcjo6YXJlYSBmdW5jdGlvbiwgdG8gcmdlb3M6OmdBcmVhIGZ1bmN0aW9uIGZvciBwb2x5Z29ucwoKZ2dwbG90KGRhdGEgPSB3ZXN0X2luZF9zaGVsZl9hcmVhcykgKwogIGdlb21fcG9pbnQoYWVzKHggPSBsYXRpdHVkZV9zdGFydCwgeSA9IGFyZWFfcmdlb3NfZ0FyZWEpLCBjb2xvciA9ICJwdXJwbGUiLCBzaXplID0gMC41KSArCiAgZ2VvbV9wb2ludChhZXMoeCA9IGxhdGl0dWRlX3N0YXJ0LCB5ID0gYXJlYV9yYXN0ZXJhcmVhKSwgY29sb3IgPSAiZGFya2dyZWVuIiwgc2l6ZSA9IDAuNSkgKwogIGdlb21fcG9pbnQoYWVzKHggPSBsYXRpdHVkZV9zdGFydCwgeSA9IGFyZWFfZXF1YWxhcmVhcHJvaiksIGNvbG9yID0gInJlZCIsIHNpemUgPSAwLjUpICsKICBsYWJzKHggPSAiTGF0aXR1ZGUiLCB5ID0gIkFyZWEga21eMiIpICsKICB0aGVtZV9jbGFzc2ljKCkKCmNvcih3ZXN0X2luZF9zaGVsZl9hcmVhc1ssMzo1XSwgdXNlID0gImNvbXBsZXRlLm9icyIpCmBgYAoKYGBge3IgcGVyY2VudCBzaGlmdCB3ZXN0ZXJuIGluZGlhbn0Kd2VzdF9pbmRfc2hlbGZfYXJlYXNbLCBwZXJjZW50X2NoYW5nZSA6PSAoYXJlYV9lcXVhbGFyZWFwcm9qLXNoaWZ0KGFyZWFfZXF1YWxhcmVhcHJvaiwgdHlwZSA9ICJsYWciKSkvc2hpZnQoYXJlYV9lcXVhbGFyZWFwcm9qLCB0eXBlID0gImxhZyIpXVssYXJlYV8xMDAwcyA6PSBhcmVhX2VxdWFsYXJlYXByb2ovMTAwMF0KCndlc3RfaW5kX3NoZWxmX2FyZWFzWywgY2hhbmdlX2Fib3ZlXzJmb2xkIDo9IGlmZWxzZSgocGVyY2VudF9jaGFuZ2U+PTEgJiBwZXJjZW50X2NoYW5nZTxJbmYpLCAxLCBpZmVsc2UocGVyY2VudF9jaGFuZ2U8PS0wLjUsIC0xLCAwKSldCgp3ZXN0X2luZF9zaGVsZl9hcmVhc19oaWdobGlnaHQgPC0gd2VzdF9pbmRfc2hlbGZfYXJlYXNbY2hhbmdlX2Fib3ZlXzJmb2xkICE9IDAsXQoKd2VzdF9pbmRfc2hlbGZfYXJlYXNfc3RhdHMgPC0gdGFibGUod2VzdF9pbmRfc2hlbGZfYXJlYXNbLC4oY2hhbmdlX2Fib3ZlXzJmb2xkKV0pCmBgYAoKRWFzdGVybiBJbmRpYW4KCmVhc3RfaW5kX3NwZGZfbWFzawoKYGBge3Igc3BsaXQgcmFzdGVyIGZvciBlYXN0ZXJuIGluZGlhbn0Kbm9ydGhfZXh0ZW50IDwtIGMoeG1pbihlYXN0X2luZF9zcGRmX21hc2tfMXMpLCB4bWF4KGVhc3RfaW5kX3NwZGZfbWFza18xcyksIDAsIHltYXgoZWFzdF9pbmRfc3BkZl9tYXNrXzFzKSkKc291dGhfZXh0ZW50IDwtIGMoeG1pbihlYXN0X2luZF9zcGRmX21hc2tfMXMpLCB4bWF4KGVhc3RfaW5kX3NwZGZfbWFza18xcyksIHltaW4oZWFzdF9pbmRfc3BkZl9tYXNrXzFzKSwgMCkKCiNjcm9wIGVhc3RfaW5kIHJhc3RlciBhYm92ZSBhbmQgYmVsb3cgMAplYXN0X2luZF9zcGRmX3NoaWZ0X2FnZ19ub3J0aCA8LSBjcm9wKGVhc3RfaW5kX3NwZGZfbWFza18xcywgZXh0ZW50KG5vcnRoX2V4dGVudCkpCgplYXN0X2luZF9zcGRmX3NoaWZ0X2FnZ19zb3V0aCA8LSBjcm9wKGVhc3RfaW5kX3NwZGZfbWFza18xcywgZXh0ZW50KHNvdXRoX2V4dGVudCkpCgojdW5mb3J0dW5hdGVseSwgSSB0aGluayBJIG1heSBoYXZlIHRvIGp1c3QgZG8gdGhpcyBtYW51YWxseSAodWdseSwgSSBrbm93KQoKI2FsbCBjaHVua3MgZm9yIGVhc3QgaW5kaWFuCmVhc3RfaW5kX25vcnRoX2xhdGl0dWRlcyA8LSBzZXEoMCwgeW1heChlYXN0X2luZF9zcGRmX21hc2tfMXMpLCBieSA9IDEpCmVhc3RfaW5kX3NvdXRoX2xhdGl0dWRlcyA8LSBzZXEoMCwgeW1pbihlYXN0X2luZF9zcGRmX21hc2tfMXMpLCBieSA9IC0xKQoKI3NldHVwIGRhdGEgdGFibGUgdG8gcG9wdWxhdGUgaW4gbG9vcCwgc3VidHJhY3Rpbmcgb25lIHRvIGFsbG93IGZvciBiaW5zCmVhc3RfaW5kX3NoZWxmX2FyZWFzIDwtIGFzLmRhdGEudGFibGUobWF0cml4KG5yb3cgPSAobGVuZ3RoKGVhc3RfaW5kX25vcnRoX2xhdGl0dWRlcyktMStsZW5ndGgoZWFzdF9pbmRfc291dGhfbGF0aXR1ZGVzKS0xKSkpCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCmVhc3RfaW5kX3NoZWxmX2FyZWFzWywgbGF0aXR1ZGVfc3RhcnQgOj0gYXMubnVtZXJpYyhWMSldWywgbGF0aXR1ZGVfZW5kIDo9IGFzLm51bWVyaWMoVjEpXVssIGFyZWFfcmFzdGVyYXJlYSA6PSBhcy5udW1lcmljKFYxKV1bLCBhcmVhX2VxdWFsYXJlYXByb2ogOj0gYXMubnVtZXJpYyhWMSldWywgYXJlYV9yZ2Vvc19nQXJlYSA6PSBhcy5udW1lcmljKFYxKV1bLCBWMSA6PSBOVUxMXQoKI2xvb3AgZm9yIG5vcnRoCmZvciAoaSBpbiAxOihsZW5ndGgoZWFzdF9pbmRfbm9ydGhfbGF0aXR1ZGVzKS0xKSkgewogICNzZXR0aW5nIHVwIGV4dGVudCBmb3Igc2xpY2luZyBieSBtaW4gYW5kIG1heCBsb25naXR1ZGVzLCBhbmQgaSB0byBpKzEgbGF0aXR1ZGVzCiAgbm9ydGhfZXh0ZW50IDwtIGMoeG1pbihlYXN0X2luZF9zcGRmX21hc2tfMXMpLCB4bWF4KGVhc3RfaW5kX3NwZGZfbWFza18xcyksIGVhc3RfaW5kX25vcnRoX2xhdGl0dWRlc1tpXSwgZWFzdF9pbmRfbm9ydGhfbGF0aXR1ZGVzW2krMV0pCiAgCiAgI2Nyb3AgcmFzdGVyIHNlZ2VtZW50IGJhc2VkIG9uIGJpbiBleHRlbnQKICBzZWdtZW50X25vcnRoIDwtIGNyb3AoZWFzdF9pbmRfc3BkZl9tYXNrXzFzLCBleHRlbnQobm9ydGhfZXh0ZW50KSkKICAKICAjcG9wdWxhdGUgZGF0YSB0YWJsZSB3aXRoIGxhdGl0dWRpbmFsIGJpbgogIGVhc3RfaW5kX3NoZWxmX2FyZWFzW2ksICJsYXRpdHVkZV9zdGFydCJdIDwtIGVhc3RfaW5kX25vcnRoX2xhdGl0dWRlc1tpXQogIGVhc3RfaW5kX3NoZWxmX2FyZWFzW2ksICJsYXRpdHVkZV9lbmQiXSA8LSBlYXN0X2luZF9ub3J0aF9sYXRpdHVkZXNbaSsxXQogIAogIGlmKGFsbChpcy5uYSh2YWx1ZXMoc2VnbWVudF9ub3J0aCkpKSkgeyAjaWYgdGhlcmUncyBubyBzaGVsZiBhcmVhIHdpdGhpbiBhIGJpbiwgYWxsIGFyZWEgPSAwCiAgICAKICBlYXN0X2luZF9zaGVsZl9hcmVhc1tpLCAiYXJlYV9lcXVhbGFyZWFwcm9qIl0gPC0gMAogIGVhc3RfaW5kX3NoZWxmX2FyZWFzW2ksICJhcmVhX3Jhc3RlcmFyZWEiXSA8LSAwCiAgZWFzdF9pbmRfc2hlbGZfYXJlYXNbaSwgImFyZWFfcmdlb3NfZ0FyZWEiXSA8LSAwCgogIAogIHByaW50KGkpCiAgICAKICB9IGVsc2UgeyAjaWYgdGhlcmUgaXMgc2hlbGYgYXJlYSB3aXRoaW4gdGhlIGJpbiwgY2FsY3VsYXRlIGFyZWEgb2Ygc2xpY2UKICAKICAgICNyYXN0ZXIgYXJlYSBjYWxjdWxhdGlvbgogICAgICAjZ2V0IHNpemVzIG9mIGFsbCBjZWxscyBpbiByYXN0ZXIgW2ttMl0KICAgIGNlbGxfc2l6ZV9yYXN0ZXI8LWFyZWEoc2VnbWVudF9ub3J0aCwgbmEucm09VFJVRSwgd2VpZ2h0cz1GQUxTRSkKICAgIAogICAgI2RlbGV0ZSBOQXMgZnJvbSB2ZWN0b3Igb2YgYWxsIHJhc3RlciBjZWxscwogICAgY2VsbF9zaXplX3Jhc3RlcjwtY2VsbF9zaXplX3Jhc3RlclshaXMubmEoc2VnbWVudF9ub3J0aCldCiAgICAKICAgICNjb21wdXRlIGFyZWEgb2YgYWxsIGNlbGxzIGluIGdlb19yYXN0ZXIKICAgICNmdWxsIGFyZWEgICAgICAgICAgPC0gdG90YWwgIyBncmlkIGNlbGxzICAgICAqIG1lZGlhbiBjZWxsIGFyZWEgKHVzaW5nIG1lZGlhbiBjYXJlcyBsZXNzIGFib3V0IGV4dHJlbWUgdmFsdWVzKQogICAgc2VnbWVudF9hcmVhX3Jhc3RlciA8LSBsZW5ndGgoY2VsbF9zaXplX3Jhc3RlcikqbWVkaWFuKGNlbGxfc2l6ZV9yYXN0ZXIpICNpbiBrbV4yCiAgICAKICAjcG9wdWxhdGUgZGF0YSB0YWJsZSB3aXRoIHJhc3RlciBhcmVhCiAgZWFzdF9pbmRfc2hlbGZfYXJlYXNbaSwgImFyZWFfcmFzdGVyYXJlYSJdIDwtIHNlZ21lbnRfYXJlYV9yYXN0ZXIKICAgIAogICNjb252ZXJ0IHRvIHNwYXRpYWwgcG9seWdvbnMgdG8gY2hlY2sgYXJlYSBjYWxjdWxhdGlvbnMKICAgIAogICNjb252ZXJ0IHNlZ21lbnQgZnJvbSByYXN0ZXIgdG8gcG9seWdvbiwgZWFjaCBjZWxsIGZyb20gdGhlIHJhc3RlciBpcyBhbiBpbmRlcGVuZGVudCBwb2x5Z29uLCAoZGlzc29sdmUgbWVhbnMgYWxsIGNlbGxzIHdpdGggYSB2YWx1ZSBvZiAxIGFyZSBhIHNpbmdsZSBwb2x5Z29uIGlmIGNvbm5lY3RlZCkKICBzZWdtZW50X25vcnRoLnNwIDwtIHJhc3RlclRvUG9seWdvbnMoc2VnbWVudF9ub3J0aCwgZGlzc29sdmUgPSBUKQogIAogICMgIElmIHggaXMgYSBTcGF0aWFsUG9seWdvbnMqIG9iamVjdDogYXJlYSBvZiBlYWNoIHNwYXRpYWwgb2JqZWN0IGluIHNxdWFyZWQgbWV0ZXJzIGlmIHRoZSBDUlMgaXMgbG9uZ2l0dWRlL2xhdGl0dWRlLCBvciBpbiBzcXVhcmVkIG1hcCB1bml0cyAodHlwaWNhbGx5IG1ldGVyKQogIAogICAgI3Byb2plY3QgdG8gZXF1YWwgZWFydGggYXJlYSBwcm9qZWN0aW9uCiAgc2VnbWVudF9ub3J0aC5zcC5FQSA8LSBzcFRyYW5zZm9ybShzZWdtZW50X25vcnRoLnNwLCBDUlNvYmogPSBlcXVhbGFyZWFwcm9qZWN0aW9uKQoKICAjY2FsY3VsYXRlIGFyZWEgb2YgdGhlIHNwYXRpYWwgb2JqZWN0IGluIG1eMgogICAgcG9seWdvbl9zaXplLnNwIDwtIGFyZWEoc2VnbWVudF9ub3J0aC5zcC5FQSkKCiAgICAjY29udmVydCBmcm9tIG1eMiB0byBrbV4yCiAgICBzZWdtZW50X2FyZWFfZXF1YWxhcmVhIDwtIHBvbHlnb25fc2l6ZS5zcC8xZTYKCiAgICAjcG9wdWxhdGUgZGF0YSB0YWJsZSB3aXRoIHBvbHlnb24gYXJlYSB1c2luZyByYXN0ZXIgY2FsY3VsYXRpb24KICBlYXN0X2luZF9zaGVsZl9hcmVhc1tpLCAiYXJlYV9lcXVhbGFyZWFwcm9qIl0gPC0gc2VnbWVudF9hcmVhX2VxdWFsYXJlYQogIAogICNhbmQgdGhlbiBwbGFpbiBhbmQgc2ltcGxlIGFsc28gdXNpbmcgcmdlb3M6OmdBcmVhCiAgCiAgYXJlYV9yZ2Vvc19nQXJlYSA8LSBnQXJlYShzZWdtZW50X25vcnRoLnNwLkVBKS8xZTYKICAKICAjcG9wdWxhdGUgZGF0YSB0YWJsZSB3aXRoIHBvbHlnb24gYXJlYSB1c2luZyByZWdlb3MgY2FsY3VsYXRpb24KICBlYXN0X2luZF9zaGVsZl9hcmVhc1tpLCAiYXJlYV9yZ2Vvc19nQXJlYSJdIDwtICAgYXJlYV9yZ2Vvc19nQXJlYQogIAogIHByaW50KGkpCiAgfSAKfQoKI2xvb3AgZm9yIHNvdXRoCmZvciAoaSBpbiAxOihsZW5ndGgoZWFzdF9pbmRfc291dGhfbGF0aXR1ZGVzKS0xKSkgewogIHNvdXRoX2V4dGVudCA8LSBjKHhtaW4oZWFzdF9pbmRfc3BkZl9tYXNrXzFzKSwgeG1heChlYXN0X2luZF9zcGRmX21hc2tfMXMpLCBlYXN0X2luZF9zb3V0aF9sYXRpdHVkZXNbaSsxXSwgZWFzdF9pbmRfc291dGhfbGF0aXR1ZGVzW2ldKSAjb3JkZXI9IHhtaW4sIHhtYXgsIHltaW4sIHltYXgpCiAgCiAgI3Jhc3RlciBzZWdtZW50CiAgc2VnbWVudF9zb3V0aCA8LSBjcm9wKGVhc3RfaW5kX3NwZGZfbWFza18xcywgZXh0ZW50KHNvdXRoX2V4dGVudCkpCiAgCiAgI2FkZCBsYXRpdHVkZSBiaW4gaW5mbyB0byBkYXRhIHRhYmxlCiAgICBlYXN0X2luZF9zaGVsZl9hcmVhc1tpKyhsZW5ndGgoZWFzdF9pbmRfbm9ydGhfbGF0aXR1ZGVzKS0xKSwgImxhdGl0dWRlX3N0YXJ0Il0gPC0gZWFzdF9pbmRfc291dGhfbGF0aXR1ZGVzW2ldCiAgZWFzdF9pbmRfc2hlbGZfYXJlYXNbaSsobGVuZ3RoKGVhc3RfaW5kX25vcnRoX2xhdGl0dWRlcyktMSksICJsYXRpdHVkZV9lbmQiXSA8LSBlYXN0X2luZF9zb3V0aF9sYXRpdHVkZXNbaSsxXQogIAogIAogIGlmKGFsbChpcy5uYSh2YWx1ZXMoc2VnbWVudF9zb3V0aCkpKSkgeyAjaWYgdGhlcmUncyBubyBzaGVsZiBhcmVhIHdpdGhpbiBhIGJpbiwgbWVhbmluZyB0aGVyZSdzIG5vIHNoZWxmIGFyZWEgYXQgdGhhdCBsYXRpdHVkZQoKICBlYXN0X2luZF9zaGVsZl9hcmVhc1tpKyhsZW5ndGgoZWFzdF9pbmRfbm9ydGhfbGF0aXR1ZGVzKS0xKSwgImFyZWFfZXF1YWxhcmVhcHJvaiJdIDwtIDAKICBlYXN0X2luZF9zaGVsZl9hcmVhc1tpKyhsZW5ndGgoZWFzdF9pbmRfbm9ydGhfbGF0aXR1ZGVzKS0xKSwgImFyZWFfcmFzdGVyYXJlYSJdIDwtIDAKICAgIGVhc3RfaW5kX3NoZWxmX2FyZWFzW2krKGxlbmd0aChlYXN0X2luZF9ub3J0aF9sYXRpdHVkZXMpLTEpLCAiYXJlYV9yZ2Vvc19nQXJlYSJdIDwtIDAKICAKICBwcmludChpKQogICAgCiAgfSBlbHNlIHsKICAKICAgICNyYXN0ZXIgYXJlYSBjYWxjdWxhdGlvbgogICAgICAjZ2V0IHNpemVzIG9mIGFsbCBjZWxscyBpbiByYXN0ZXIgW2ttMl0KICAgIGNlbGxfc2l6ZV9yYXN0ZXI8LWFyZWEoc2VnbWVudF9zb3V0aCwgbmEucm09VFJVRSwgd2VpZ2h0cz1GQUxTRSkKICAgIAogICAgI2RlbGV0ZSBOQXMgZnJvbSB2ZWN0b3Igb2YgYWxsIHJhc3RlciBjZWxscwogICAgY2VsbF9zaXplX3Jhc3RlcjwtY2VsbF9zaXplX3Jhc3RlclshaXMubmEoc2VnbWVudF9zb3V0aCldCiAgICAjY29tcHV0ZSBhcmVhIG9mIGFsbCBjZWxscyBpbiBnZW9fcmFzdGVyCiAgICAjZnVsbCBhcmVhICAgICAgICAgIDwtIHRvdGFsICMgZ3JpZCBjZWxscyAgICAgKiBtZWRpYW4gY2VsbCBhcmVhICh1c2luZyBtZWRpYW4gY2FyZXMgbGVzcyBhYm91dCBleHRyZW1lIHZhbHVlcykKICAgIHNlZ21lbnRfYXJlYV9yYXN0ZXIgPC0gbGVuZ3RoKGNlbGxfc2l6ZV9yYXN0ZXIpKm1lZGlhbihjZWxsX3NpemVfcmFzdGVyKQogICAgCiAgI3BvcHVsYXRlIGRhdGEgdGFibGUgd2l0aCByYXN0ZXIgYXJlYQogIGVhc3RfaW5kX3NoZWxmX2FyZWFzW2krKGxlbmd0aChlYXN0X2luZF9ub3J0aF9sYXRpdHVkZXMpLTEpLCAiYXJlYV9yYXN0ZXJhcmVhIl0gPC0gc2VnbWVudF9hcmVhX3Jhc3RlcgogICAgCiAgCiAgI2NvbnZlcnQgdG8gc3BhdGlhbCBwb2x5Z29ucyB0byBjaGVjayBhcmVhIGNhbGN1bGF0aW9ucwogICAgCiAgI2NvbnZlcnQgc2VnbWVudCBmcm9tIHJhc3RlciB0byBwb2x5Z29uLCBlYWNoIGNlbGwgZnJvbSB0aGUgcmFzdGVyIGlzIGFuIGluZGVwZW5kZW50IHBvbHlnb24sIChkaXNzb2x2ZSBtZWFucyBhbGwgY2VsbHMgd2l0aCBhIHZhbHVlIG9mIDEgYXJlIGEgc2luZ2xlIHBvbHlnb24gaWYgY29ubmVjdGVkKQogIHNlZ21lbnRfc291dGguc3AgPC0gcmFzdGVyVG9Qb2x5Z29ucyhzZWdtZW50X3NvdXRoLCBkaXNzb2x2ZSA9IFQpCiAgCiAgIyAgSWYgeCBpcyBhIFNwYXRpYWxQb2x5Z29ucyogb2JqZWN0OiBhcmVhIG9mIGVhY2ggc3BhdGlhbCBvYmplY3QgaW4gc3F1YXJlZCBtZXRlcnMgaWYgdGhlIENSUyBpcyBsb25naXR1ZGUvbGF0aXR1ZGUsIG9yIGluIHNxdWFyZWQgbWFwIHVuaXRzICh0eXBpY2FsbHkgbWV0ZXIpCiAgCiAgICAjcHJvamVjdCB0byBlcXVhbCBlYXJ0aCBhcmVhIHByb2plY3Rpb24KICBzZWdtZW50X3NvdXRoLnNwLkVBIDwtIHNwVHJhbnNmb3JtKHNlZ21lbnRfc291dGguc3AsIENSU29iaiA9IGVxdWFsYXJlYXByb2plY3Rpb24pCgogICNjYWxjdWxhdGUgYXJlYSBvZiB0aGUgc3BhdGlhbCBvYmplY3QgaW4gbV4yCiAgICBwb2x5Z29uX3NpemUuc3AgPC0gYXJlYShzZWdtZW50X3NvdXRoLnNwLkVBKQoKICAgICNjb252ZXJ0IGZyb20gbV4yIHRvIGttXjIKICAgIHNlZ21lbnRfYXJlYV9lcXVhbGFyZWEgPC0gcG9seWdvbl9zaXplLnNwLzFlNgoKICAgICNwb3B1bGF0ZSBkYXRhIHRhYmxlIHdpdGggYXJlYSBvZiBwb2x5Z29uIGZyb20gcmFzdGVyOjphcmVhIGZ1bmN0aW9uCiAgZWFzdF9pbmRfc2hlbGZfYXJlYXNbaSsobGVuZ3RoKGVhc3RfaW5kX25vcnRoX2xhdGl0dWRlcyktMSksICJhcmVhX2VxdWFsYXJlYXByb2oiXSA8LSBzZWdtZW50X2FyZWFfZXF1YWxhcmVhCiAgCiAgI2FuZCB0aGVuIHBsYWluIGFuZCBzaW1wbGUgYWxzbyB1c2luZyByZ2Vvczo6Z0FyZWEKICAKICBhcmVhX3JnZW9zX2dBcmVhIDwtIGdBcmVhKHNlZ21lbnRfc291dGguc3AuRUEpLzFlNgogIAogICNwb3B1bGF0ZSBkYXRhIHRhYmxlIGZyb20gcmdlb3MgYXJlYSBjYWxjdWxhdGlvbiBmb3IgcHJvamVjdGVkIHBvbHlnb24KICBlYXN0X2luZF9zaGVsZl9hcmVhc1tpKyhsZW5ndGgoZWFzdF9pbmRfbm9ydGhfbGF0aXR1ZGVzKS0xKSwgImFyZWFfcmdlb3NfZ0FyZWEiXSA8LSAgIGFyZWFfcmdlb3NfZ0FyZWEKICAKICBwcmludChpKQogIH0gCn0KCiNjb21wYXJlIHJhc3RlcjphcmVhIGNhbGN1bGF0aW9uLCB0byBlcXVhbCBhcmVhIHN0aWxsIHVzaW5nIHJhc3Rlcjo6YXJlYSBmdW5jdGlvbiwgdG8gcmdlb3M6OmdBcmVhIGZ1bmN0aW9uIGZvciBwb2x5Z29ucwoKZ2dwbG90KGRhdGEgPSBlYXN0X2luZF9zaGVsZl9hcmVhcykgKwogIGdlb21fcG9pbnQoYWVzKHggPSBsYXRpdHVkZV9zdGFydCwgeSA9IGFyZWFfcmdlb3NfZ0FyZWEpLCBjb2xvciA9ICJwdXJwbGUiLCBzaXplID0gMC41KSArCiAgZ2VvbV9wb2ludChhZXMoeCA9IGxhdGl0dWRlX3N0YXJ0LCB5ID0gYXJlYV9yYXN0ZXJhcmVhKSwgY29sb3IgPSAiZGFya2dyZWVuIiwgc2l6ZSA9IDAuNSkgKwogIGdlb21fcG9pbnQoYWVzKHggPSBsYXRpdHVkZV9zdGFydCwgeSA9IGFyZWFfZXF1YWxhcmVhcHJvaiksIGNvbG9yID0gInJlZCIsIHNpemUgPSAwLjUpICsKICBsYWJzKHggPSAiTGF0aXR1ZGUiLCB5ID0gIkFyZWEga21eMiIpICsKICB0aGVtZV9jbGFzc2ljKCkKCmNvcihlYXN0X2luZF9zaGVsZl9hcmVhc1ssMzo1XSwgdXNlID0gImNvbXBsZXRlLm9icyIpCgpgYGAKCmBgYHtyIHBlcmNlbnQgc2hpZnQgZWFzdGVybiBpbmRpYW59CmVhc3RfaW5kX3NoZWxmX2FyZWFzWywgcGVyY2VudF9jaGFuZ2UgOj0gKGFyZWFfZXF1YWxhcmVhcHJvai1zaGlmdChhcmVhX2VxdWFsYXJlYXByb2osIHR5cGUgPSAibGFnIikpL3NoaWZ0KGFyZWFfZXF1YWxhcmVhcHJvaiwgdHlwZSA9ICJsYWciKV1bLGFyZWFfMTAwMHMgOj0gYXJlYV9lcXVhbGFyZWFwcm9qLzEwMDBdCgplYXN0X2luZF9zaGVsZl9hcmVhc1ssIGNoYW5nZV9hYm92ZV8yZm9sZCA6PSBpZmVsc2UoKHBlcmNlbnRfY2hhbmdlPj0xICYgcGVyY2VudF9jaGFuZ2U8SW5mKSwgMSwgaWZlbHNlKHBlcmNlbnRfY2hhbmdlPD0tMC41LCAtMSwgMCkpXQoKZWFzdF9pbmRfc2hlbGZfYXJlYXNfaGlnaGxpZ2h0IDwtIGVhc3RfaW5kX3NoZWxmX2FyZWFzW2NoYW5nZV9hYm92ZV8yZm9sZCAhPSAwLF0KCmVhc3RfaW5kX3NoZWxmX2FyZWFzX3N0YXRzIDwtIHRhYmxlKGVhc3RfaW5kX3NoZWxmX2FyZWFzWywuKGNoYW5nZV9hYm92ZV8yZm9sZCldKQpgYGAKClBsb3RzIG9mIGxhdGl0dWRlIHZlcnN1cyBoYWJpdGF0IGF2YWlsYWJpbGl0eQoKYGBge3IgcGxvdHMgbGF0aXR1ZGUgaGFiaXRhdCBhdmFpbGFiaWxpdHl9CihhcmVhX2xhdGl0dWRlX2Vhc3RfaW5kICA8LSBnZ3Bsb3QoKSArCiAgZ2VvbV9wb2ludChkYXRhID0gZWFzdF9pbmRfc2hlbGZfYXJlYXMsIGFlcyh4PWxhdGl0dWRlX3N0YXJ0LCB5PWFyZWFfMTAwMHMpLCBzaGFwZSA9MTgpICsKICBnZW9tX2xpbmUoZGF0YSA9IGVhc3RfaW5kX3NoZWxmX2FyZWFzLCBhZXMoeD1sYXRpdHVkZV9zdGFydCwgeT1hcmVhXzEwMDBzKSkgKwogIGdlb21fcnVnKGRhdGEgPSBlYXN0X2luZF9zaGVsZl9hcmVhc19oaWdobGlnaHQsIGFlcyh4ID0gbGF0aXR1ZGVfc3RhcnQsIGNvbG9yID0gYXMuZmFjdG9yKGNoYW5nZV9hYm92ZV8yZm9sZCkpKSArCiBsYWJzKHggPSAiTGF0aXR1ZGUiLCB5ID0gZXhwcmVzc2lvbihwYXN0ZSgiQXJlYSAoMTAwMHMgb2YgIiwga21eezJ9LCIpIikpKSArCiAgc2NhbGVfY29sb3JfZGlzY3JldGUobmFtZSA9ICJJbnN0YW5jZXMgb2YgMiBGb2xkXG4gSGFiaXRhdCBDaGFuZ2UiLCBsYWJlbHMgPSBjKCJDb250cmFjdGlvbiIsICJFeHBhbnNpb24iKSkgKwogICMjYW5ub3RhdGUoInRleHQiLCB4ID0yMiwgeSA9IDcwMDAwLCBsYWJlbCA9ICJFYXN0ZXJuIEluZGlhbiBPY2VhbiIpICsKICBnZW9tX3ZsaW5lKHhpbnRlcmNlcHQgPSAwKSArCiAgeGxpbShtaW4oZWFzdF9pbmRfc2hlbGZfYXJlYXMkbGF0aXR1ZGVfZW5kKSwgbWF4KGVhc3RfaW5kX3NoZWxmX2FyZWFzJGxhdGl0dWRlX2VuZCkpICsKICBjb29yZF9mbGlwKCkgKwogIHRoZW1lX2NsYXNzaWMoKSArCiAgdGhlbWUocGxvdC5tYXJnaW4gPSBtYXJnaW4oMTAsIDQwLCAxMCwgMTApKSkKCgogIGdnc2F2ZShhcmVhX2xhdGl0dWRlX2Vhc3RfaW5kLCBmaWxlbmFtZSA9ICJhcmVhX2xhdGl0dWRlX2Vhc3RfaW5kLmpwZyIsIGhlaWdodCA9IDQsIHVuaXRzID0gYygiaW4iKSkKCmFyZWFfbGF0aXR1ZGVfd2VzdF9pbmQgIDwtIGdncGxvdCgpICsKICBnZW9tX3BvaW50KGRhdGEgPSB3ZXN0X2luZF9zaGVsZl9hcmVhcywgYWVzKHg9bGF0aXR1ZGVfc3RhcnQsIHk9YXJlYV8xMDAwcyksIHNoYXBlID0xOCkgKyAKICBnZW9tX2xpbmUoZGF0YSA9IHdlc3RfaW5kX3NoZWxmX2FyZWFzLCBhZXMoeD1sYXRpdHVkZV9zdGFydCwgeT1hcmVhXzEwMDBzKSkgKwogICAgZ2VvbV9ydWcoZGF0YSA9IGVhc3RfaW5kX3NoZWxmX2FyZWFzX2hpZ2hsaWdodCwgYWVzKHggPSBsYXRpdHVkZV9zdGFydCwgY29sb3IgPSBhcy5mYWN0b3IoY2hhbmdlX2Fib3ZlXzJmb2xkKSkpICsKIGxhYnMoeCA9ICJMYXRpdHVkZSIsIHkgPSBleHByZXNzaW9uKHBhc3RlKCJBcmVhICgxMDAwcyBvZiAiLCBrbV57Mn0sIikiKSkpICsKICBzY2FsZV9jb2xvcl9kaXNjcmV0ZShuYW1lID0gIkluc3RhbmNlcyBvZiAyIEZvbGRcbiBIYWJpdGF0IENoYW5nZSIsIGxhYmVscyA9IGMoIkNvbnRyYWN0aW9uIiwgIkV4cGFuc2lvbiIpKSArCiAgI2Fubm90YXRlKCJ0ZXh0IiwgeCA9IDMwLCB5ID0gMzMwMDAsIGxhYmVsID0gIldlc3Rlcm4gSW5kaWFuIE9jZWFuIikgKwogIGdlb21fdmxpbmUoeGludGVyY2VwdCA9IDApICsKICB4bGltKG1pbih3ZXN0X2luZF9zaGVsZl9hcmVhcyRsYXRpdHVkZV9lbmQpLCBtYXgod2VzdF9pbmRfc2hlbGZfYXJlYXMkbGF0aXR1ZGVfZW5kKSkgKwogIGNvb3JkX2ZsaXAoKSArCiAgdGhlbWVfY2xhc3NpYygpICsKICB0aGVtZShwbG90Lm1hcmdpbiA9IG1hcmdpbigxMCwgNDAsIDEwLCAxMCkpCgogIGdnc2F2ZShhcmVhX2xhdGl0dWRlX3dlc3RfaW5kLCBmaWxlbmFtZSA9ICJhcmVhX2xhdGl0dWRlX3dlc3RfaW5kLmpwZyIsIGhlaWdodCA9IDQsIHVuaXRzID0gYygiaW4iKSkKCmFyZWFfbGF0aXR1ZGVfd2VzdF9hdGwgIDwtIGdncGxvdCgpICsKICBnZW9tX3BvaW50KGRhdGEgPSB3ZXN0X2F0bF9zaGVsZl9hcmVhcywgYWVzKHg9bGF0aXR1ZGVfc3RhcnQsIHk9YXJlYV8xMDAwcyksIHNoYXBlID0xOCkgKyAKICBnZW9tX2xpbmUoZGF0YSA9IHdlc3RfYXRsX3NoZWxmX2FyZWFzLCBhZXMoeD1sYXRpdHVkZV9zdGFydCwgeT1hcmVhXzEwMDBzKSkgKwogIGdlb21fcnVnKGRhdGEgPSB3ZXN0X2F0bF9zaGVsZl9hcmVhc19oaWdobGlnaHQsIGFlcyh4ID0gbGF0aXR1ZGVfc3RhcnQsIGNvbG9yID0gYXMuZmFjdG9yKGNoYW5nZV9hYm92ZV8yZm9sZCkpKSArCiBsYWJzKHggPSAiTGF0aXR1ZGUiLCB5ID0gZXhwcmVzc2lvbihwYXN0ZSgiQXJlYSAoMTAwMHMgb2YgIiwga21eezJ9LCIpIikpKSArCiAgc2NhbGVfY29sb3JfZGlzY3JldGUobmFtZSA9ICJJbnN0YW5jZXMgb2YgMiBGb2xkXG4gSGFiaXRhdCBDaGFuZ2UiLCBsYWJlbHMgPSBjKCJDb250cmFjdGlvbiIsICJFeHBhbnNpb24iKSkgKwogICNhbm5vdGF0ZSgidGV4dCIsIHggPSA4MCwgeSA9IDEyMDAwMCwgbGFiZWwgPSAiV2VzdGVybiBBdGxhbnRpYyBPY2VhbiIpICsKICBnZW9tX3ZsaW5lKHhpbnRlcmNlcHQgPSAwKSArCiAgeGxpbShtaW4od2VzdF9hdGxfc2hlbGZfYXJlYXMkbGF0aXR1ZGVfZW5kKSwgbWF4KHdlc3RfYXRsX3NoZWxmX2FyZWFzJGxhdGl0dWRlX2VuZCkpICsKICBjb29yZF9mbGlwKCkgKwogIHRoZW1lX2NsYXNzaWMoKSArCiAgdGhlbWUocGxvdC5tYXJnaW4gPSBtYXJnaW4oMTAsIDQwLCAxMCwgMTApKQoKICBnZ3NhdmUoYXJlYV9sYXRpdHVkZV93ZXN0X2F0bCwgZmlsZW5hbWUgPSAiYXJlYV9sYXRpdHVkZV93ZXN0X2F0bC5qcGciLCBoZWlnaHQgPSA0LCB1bml0cyA9IGMoImluIikpCgphcmVhX2xhdGl0dWRlX2Vhc3RfYXRsICA8LSBnZ3Bsb3QoKSArCiAgZ2VvbV9wb2ludChkYXRhID0gZWFzdF9hdGxfc2hlbGZfYXJlYXMsIGFlcyh4PWxhdGl0dWRlX3N0YXJ0LCB5PWFyZWFfMTAwMHMpLCBzaGFwZSA9MTgpICsgCiAgZ2VvbV9saW5lKGRhdGEgPSBlYXN0X2F0bF9zaGVsZl9hcmVhcywgYWVzKHg9bGF0aXR1ZGVfc3RhcnQsIHk9YXJlYV8xMDAwcykpICsKICBnZW9tX3J1ZyhkYXRhID0gZWFzdF9hdGxfc2hlbGZfYXJlYXNfaGlnaGxpZ2h0LCBhZXMoeCA9IGxhdGl0dWRlX3N0YXJ0LCBjb2xvciA9IGFzLmZhY3RvcihjaGFuZ2VfYWJvdmVfMmZvbGQpKSkgKwogbGFicyh4ID0gIkxhdGl0dWRlIiwgeSA9IGV4cHJlc3Npb24ocGFzdGUoIkFyZWEgKDEwMDBzIG9mICIsIGttXnsyfSwiKSIpKSkgKwogIHNjYWxlX2NvbG9yX2Rpc2NyZXRlKG5hbWUgPSAiSW5zdGFuY2VzIG9mIDIgRm9sZFxuIEhhYml0YXQgQ2hhbmdlIiwgbGFiZWxzID0gYygiQ29udHJhY3Rpb24iLCAiRXhwYW5zaW9uIikpICsKICAjYW5ub3RhdGUoInRleHQiLCB4ID0gODIuNSwgeSA9IDExMDAwMCwgbGFiZWwgPSAiRWFzdGVybiBBdGxhbnRpYyBPY2VhbiIpICsKICBnZW9tX3ZsaW5lKHhpbnRlcmNlcHQgPSAwKSArCiAgeGxpbShtaW4oZWFzdF9hdGxfc2hlbGZfYXJlYXMkbGF0aXR1ZGVfZW5kKSwgbWF4KGVhc3RfYXRsX3NoZWxmX2FyZWFzJGxhdGl0dWRlX2VuZCkpICsKICBjb29yZF9mbGlwKCkgKwogIHRoZW1lX2NsYXNzaWMoKSArCiAgdGhlbWUocGxvdC5tYXJnaW4gPSBtYXJnaW4oMTAsIDQwLCAxMCwgMTApKQoKICBnZ3NhdmUoYXJlYV9sYXRpdHVkZV9lYXN0X2F0bCwgZmlsZW5hbWUgPSAiYXJlYV9sYXRpdHVkZV9lYXN0X2F0bC5qcGciLCBoZWlnaHQgPSA0LCB1bml0cyA9IGMoImluIikpCgphcmVhX2xhdGl0dWRlX2Vhc3RfcGFjICA8LSBnZ3Bsb3QoKSArCiAgZ2VvbV9wb2ludChkYXRhID0gZWFzdF9wYWNfc2hlbGZfYXJlYXMsIGFlcyh4PWxhdGl0dWRlX3N0YXJ0LCB5PWFyZWFfMTAwMHMpLCBzaGFwZSA9MTgpICsgCiAgZ2VvbV9saW5lKGRhdGEgPSBlYXN0X3BhY19zaGVsZl9hcmVhcywgYWVzKHg9bGF0aXR1ZGVfc3RhcnQsIHk9YXJlYV8xMDAwcykpICsKICBnZW9tX3J1ZyhkYXRhID0gZWFzdF9wYWNfc2hlbGZfYXJlYXNfaGlnaGxpZ2h0LCBhZXMoeCA9IGxhdGl0dWRlX3N0YXJ0LCBjb2xvciA9IGFzLmZhY3RvcihjaGFuZ2VfYWJvdmVfMmZvbGQpKSkgKwogbGFicyh4ID0gIkxhdGl0dWRlIiwgeSA9IGV4cHJlc3Npb24ocGFzdGUoIkFyZWEgKDEwMDBzIG9mICIsIGttXnsyfSwiKSIpKSkgKwogIHNjYWxlX2NvbG9yX2Rpc2NyZXRlKG5hbWUgPSAiSW5zdGFuY2VzIG9mIDIgRm9sZFxuIEhhYml0YXQgQ2hhbmdlIiwgbGFiZWxzID0gYygiQ29udHJhY3Rpb24iLCAiRXhwYW5zaW9uIikpICsKICAjYW5ub3RhdGUoInRleHQiLCB4ID0gODAsIHkgPSAxMzAwMDAsIGxhYmVsID0gIkVhc3Rlcm4gUGFjaWZpYyBPY2VhbiIpICsKICBnZW9tX3ZsaW5lKHhpbnRlcmNlcHQgPSAwKSArCiAgeGxpbShtaW4oZWFzdF9wYWNfc2hlbGZfYXJlYXMkbGF0aXR1ZGVfZW5kKSwgbWF4KGVhc3RfcGFjX3NoZWxmX2FyZWFzJGxhdGl0dWRlX2VuZCkpICsKICBjb29yZF9mbGlwKCkgKwogIHRoZW1lX2NsYXNzaWMoKSArCiAgdGhlbWUocGxvdC5tYXJnaW4gPSBtYXJnaW4oMTAsIDQwLCAxMCwgMTApKQoKICBnZ3NhdmUoYXJlYV9sYXRpdHVkZV9lYXN0X3BhYywgZmlsZW5hbWUgPSAiYXJlYV9sYXRpdHVkZV9lYXN0X3BhYy5qcGciLCBoZWlnaHQgPSA0LCB1bml0cyA9IGMoImluIikpCgoKKGFyZWFfbGF0aXR1ZGVfd2VzdF9wYWMgPC0gZ2dwbG90KCkgKwogIGdlb21fcG9pbnQoZGF0YSA9IHdlc3RfcGFjX3NoZWxmX2FyZWFzLCBhZXMoeD1sYXRpdHVkZV9zdGFydCwgeT1hcmVhXzEwMDBzKSwgc2hhcGUgPTE4KSArIAogIGdlb21fbGluZShkYXRhID0gd2VzdF9wYWNfc2hlbGZfYXJlYXMsIGFlcyh4PWxhdGl0dWRlX3N0YXJ0LCB5PWFyZWFfMTAwMHMpKSArCiAgI2dlb21fcG9pbnQoZGF0YSA9IHdlc3RfcGFjX3NoZWxmX2FyZWFzX2hpZ2hsaWdodCwgYWVzKHggPSBsYXRpdHVkZV9zdGFydCwgeSA9IGFyZWEpLCBzaGFwZSA9MTksIGNvbG9yID0gInNlYWdyZWVuNCIsIHNpemUgPSAyKSArIAogIGdlb21fcnVnKGRhdGEgPSB3ZXN0X3BhY19zaGVsZl9hcmVhc19oaWdobGlnaHQsIGFlcyh4ID0gbGF0aXR1ZGVfc3RhcnQsIGNvbG9yID0gYXMuZmFjdG9yKGNoYW5nZV9hYm92ZV8yZm9sZCkpKSArCiBsYWJzKHggPSAiTGF0aXR1ZGUiLCB5ID0gZXhwcmVzc2lvbihwYXN0ZSgiQXJlYSAoMTAwMHMgb2YgIiwga21eezJ9LCIpIikpKSArCiAgc2NhbGVfY29sb3JfZGlzY3JldGUobmFtZSA9ICJJbnN0YW5jZXMgb2YgMiBGb2xkXG4gSGFiaXRhdCBDaGFuZ2UiLCBsYWJlbHMgPSBjKCJDb250cmFjdGlvbiIsICJFeHBhbnNpb24iKSkgKwogICNhbm5vdGF0ZSgidGV4dCIsIHggPSA5MCwgeSA9IDEzMDAwMCwgbGFiZWwgPSAiV2VzdGVybiBQYWNpZmljIE9jZWFuIikgKwogIGdlb21fdmxpbmUoeGludGVyY2VwdCA9IDApICsKICB4bGltKG1pbih3ZXN0X3BhY19zaGVsZl9hcmVhcyRsYXRpdHVkZV9lbmQpLCBtYXgod2VzdF9wYWNfc2hlbGZfYXJlYXMkbGF0aXR1ZGVfZW5kKSkgKwogIGNvb3JkX2ZsaXAoKSArCiAgdGhlbWVfY2xhc3NpYygpICsKICB0aGVtZShwbG90Lm1hcmdpbiA9IG1hcmdpbigxMCwgNDAsIDEwLCAxMCkpKQoKICAKCiAgZ2dzYXZlKGFyZWFfbGF0aXR1ZGVfd2VzdF9wYWMsIGZpbGVuYW1lID0gImFyZWFfbGF0aXR1ZGVfd2VzdF9wYWMuanBnIiwgaGVpZ2h0ID0gNCwgdW5pdHMgPSBjKCJpbiIpKQoKYGBgCgpIb3cgbWFueSBleHBlcmllbmNlICdzaWduaWZpY2FudCcgY2hhbmdlcyBpbiBoYWJpdGF0IChhdCBsZWFzdCAtNTAlIG9yICsyMDAlIGNoYW5nZSBmcm9tIG9uZSBiaW4gdG8gYW5vdGhlcikgSSB3aWxsIGdvIHdpdGggSVVDTiA1MCUgbG9zcyAtPiB2dWxuZXJhYmxlIHNwZWNpZXMgZGVzaWduYXRpb24uCgpCaW4gc2hpZnRzIC0tPiBjb250cmFjdGlvbnMgKGxvc3Mgb2YgNTAlKSB2ZXJzdXMgZXhwYW5zaW9ucyAoZ2FpbiBvZiAyMDAlKSB2ZXJzdXMgbmV1dHJhbApgYGB7ciBiaW4gc2hpZnQgY2F0ZWdvcml6YXRpb259CiNjYWxsIGFsbCBvYmplY3RzIGluIGVudmlyb25tZW50IHdpdGggInN0YXRzIiBzdHJpbmcKc3RhdHNfc3RyaW5nPC1ncmVwKCJfc3RhdHMiLG5hbWVzKC5HbG9iYWxFbnYpLHZhbHVlPVRSVUUpCnN0YXRzX3N0cmluZ19saXN0PC1kby5jYWxsKCJsaXN0IixtZ2V0KHN0YXRzX3N0cmluZykpCm5hbWVzKHN0YXRzX3N0cmluZ19saXN0KSA8LSBjKCJFYXN0ZXJuIEluZGlhbiBPY2VhbiIgLCJXZXN0ZXJuIFBhY2lmaWMgT2NlYW4iICwiRWFzdGVybiBQYWNpZmljIE9jZWFuIiAsIldlc3Rlcm4gQXRsYW50aWMgT2NlYW4iICwiV2VzdGVybiBJbmRpYW4gT2NlYW4iICwiRWFzdGVybiBBdGxhbnRpYyBPY2VhbiIpCgpzaWduaWZpY2FudF9jaGFuZ2VzIDwtIGFzLmRhdGEudGFibGUocmJpbmQoc3RhdHNfc3RyaW5nX2xpc3RbWzFdXSxzdGF0c19zdHJpbmdfbGlzdFtbMl1dLHN0YXRzX3N0cmluZ19saXN0W1szXV0sc3RhdHNfc3RyaW5nX2xpc3RbWzRdXSxzdGF0c19zdHJpbmdfbGlzdFtbNV1dLHN0YXRzX3N0cmluZ19saXN0W1s2XV0pKQoKY29sbmFtZXMoc2lnbmlmaWNhbnRfY2hhbmdlcykgPC0gYygiY29udHJhY3Rpb24iLCAibmV1dHJhbCIsICJleHBhbnNpb24iKQoKc2lnbmlmaWNhbnRfY2hhbmdlc1ssIHJlZ2lvbiA6PSBuYW1lcyhzdGF0c19zdHJpbmdfbGlzdCldWyx0b3RhbF9iaW5zIDo9IGNvbnRyYWN0aW9uICsgbmV1dHJhbCArIGV4cGFuc2lvbl1bLGNvbnRyYWN0aW9uX3BlcmNlbnQgOj0gY29udHJhY3Rpb24vdG90YWxfYmluc11bLG5ldXRyYWxfcGVyY2VudCA6PSBuZXV0cmFsL3RvdGFsX2JpbnNdWyxleHBhbnNpb25fcGVyY2VudCA6PSBleHBhbnNpb24vdG90YWxfYmluc10KCiNtZWx0IHRvIHBsb3QKc2lnbmlmaWNhbnRfY2hhbmdlcy5sb25nIDwtIG1lbHQoc2lnbmlmaWNhbnRfY2hhbmdlcywgaWQudmFycyA9IGMoInJlZ2lvbiIpLCB2YXJpYWJsZS5uYW1lID0gImNoYW5nZV90eXBlIiwgbWVhc3VyZS52YXJzID0gYygiY29udHJhY3Rpb25fcGVyY2VudCIsICJuZXV0cmFsX3BlcmNlbnQiLCAiZXhwYW5zaW9uX3BlcmNlbnQiKSkKCmJsYW5rX3RoZW1lIDwtIHRoZW1lX21pbmltYWwoKSsKICB0aGVtZSgKICBheGlzLnRpdGxlLnggPSBlbGVtZW50X2JsYW5rKCksCiAgYXhpcy50aXRsZS55ID0gZWxlbWVudF9ibGFuaygpLAogIHBhbmVsLmJvcmRlciA9IGVsZW1lbnRfYmxhbmsoKSwKICBwYW5lbC5ncmlkPWVsZW1lbnRfYmxhbmsoKSwKICBheGlzLnRpY2tzID0gZWxlbWVudF9ibGFuaygpLAogIHBsb3QudGl0bGU9ZWxlbWVudF90ZXh0KHNpemU9MTQsIGZhY2U9ImJvbGQiKQogICkKCmdncGxvdChkYXRhID0gc2lnbmlmaWNhbnRfY2hhbmdlcy5sb25nLCBhZXMoeD0iIiwgeSA9IHZhbHVlLCBmaWxsID0gY2hhbmdlX3R5cGUpKSArCiAgZ2VvbV9iYXIoc3RhdCA9ICJpZGVudGl0eSIsIHdpZHRoID0gMSkgKwogIGNvb3JkX3BvbGFyKCJ5Iiwgc3RhcnQ9MCkgKwogIHNjYWxlX2ZpbGxfbWFudWFsKHZhbHVlcyA9IGMoImRhcmtzYWxtb24iLCAiYXp1cmUyIiwgImN5YW4zIiksIG5hbWUgPSAiSGFiaXRhdCBDaGFuZ2UiLCBsYWJlbHMgPSBjKCI+PSAyIEZvbGQgQ29udHJhY3Rpb24iLCAiPCAyIEZvbGQgQ2hhbmdlIiwgIj49IDIgRm9sZCBFeHBhbnNpb24iKSkgKwogIGZhY2V0X3dyYXAofnJlZ2lvbikgKwogIGdlb21fdGV4dChhZXMobGFiZWwgPSBwYXN0ZTAocm91bmQodmFsdWUqMTAwLDEpLCIlIikpLCBwb3NpdGlvbiA9IHBvc2l0aW9uX3N0YWNrKHZqdXN0ID0gMC4xKSwgc2l6ZSA9IDIpICsKICBzY2FsZV94X2Rpc2NyZXRlKGV4cGFuZCA9IGMoMCwwKSkgKwogIGJsYW5rX3RoZW1lICsKICB0aGVtZShheGlzLnRleHQueD1lbGVtZW50X2JsYW5rKCkpCgpnZ3NhdmUoZmlsZW5hbWUgPSAiaGFiaXRhdGxvc3NfZ2Fpbl8yZm9sZC5wZGYiKQpgYGAKCk5vdywgSSBzaG91bGQgbWFrZSBtYXBzIGZvciBlYWNoIG9mIHRoZXNlIHJlZ2lvbnMKClVzZWQgaHR0cHM6Ly9naXN0LmdpdGh1Yi5jb20vdmFsZW50aW5pdG5lbGF2L2M3NTk4ZmNmYzhlNTM2NThmNjZmZWVhOWQzYmFmYjQwIGZvciBpbnN0cnVjdGlvbnMKCmBgYHtyIHNldHVwIHdvcmxkIG1hcHN9CmxpYnJhcnkoZ2dzcGF0aWFsKQoKICB3b3JsZCA8LSBuZV9jb3VudHJpZXMoc2NhbGUgPSAibWVkaXVtIiwgcmV0dXJuY2xhc3MgPSAic2YiKQoKIyB+fn5+fn5+fn5+fiBEb3dubG9hZCBzaGFwZWZpbGUgZnJvbSB3d3cubmF0dXJhbGVhcnRoZGF0YS5jb20gfn5+fn5+fn5+fn4gIwojIERvd25sb2FkIGNvdW50cmllcyBkYXRhCmRvd25sb2FkLmZpbGUodXJsID0gImh0dHA6Ly93d3cubmF0dXJhbGVhcnRoZGF0YS5jb20vaHR0cC8vd3d3Lm5hdHVyYWxlYXJ0aGRhdGEuY29tL2Rvd25sb2FkLzExMG0vY3VsdHVyYWwvbmVfMTEwbV9hZG1pbl8wX2NvdW50cmllcy56aXAiLCAKICAgICAgICAgICAgICBkZXN0ZmlsZSA9ICJuZV8xMTBtX2FkbWluXzBfY291bnRyaWVzLnppcCIpCiMgdW56aXAgdGhlIHNoYXBlZmlsZSBpbiB0aGUgZGlyZWN0b3J5IG1lbnRpb25lZCB3aXRoICJleGRpciIgYXJndW1lbnQKdW56aXAoemlwZmlsZT0ibmVfMTEwbV9hZG1pbl8wX2NvdW50cmllcy56aXAiLCBleGRpciA9ICJuZV8xMTBtX2FkbWluXzBfY291bnRyaWVzIikKIyBkZWxldGUgdGhlIHppcCBmaWxlCmZpbGUucmVtb3ZlKCJuZV8xMTBtX2FkbWluXzBfY291bnRyaWVzLnppcCIpCiMgcmVhZCB0aGUgc2hhcGVmaWxlIHdpdGggcmVhZE9HUiBmcm9tIHJnZGFsIHBhY2thZ2UKTkVfY291bnRyaWVzIDwtIHJlYWRPR1IoZHNuID0gIm5lXzExMG1fYWRtaW5fMF9jb3VudHJpZXMiLCBsYXllciA9ICJuZV8xMTBtX2FkbWluXzBfY291bnRyaWVzIikKY2xhc3MoTkVfY291bnRyaWVzKSAjIGlzIGEgU3BhdGlhbFBvbHlnb25zRGF0YUZyYW1lIG9iamVjdAoKIyB+fn5+fn5+fn5+fiBTcGxpdCB3b3JsZCBtYXAgYnkgInNwbGl0IGxpbmUiIH5+fn5+fn5+fn5+ICMKCiMgc2hpZnQgY2VudHJhbC9wcmltZSBtZXJpZGlhbiB0b3dhcmRzIHdlc3Qg4oCTIHBvc2l0aXZlIHZhbHVlcyBvbmx5CnNoaWZ0IDwtIDE4MCArMzAKCiMgY3JlYXRlICJzcGxpdCBsaW5lIiB0byBzcGxpdCBjb3VudHJ5IHBvbHlnb25zCldHUzg0IDwtIENSUygiK3Byb2o9bG9uZ2xhdCArZGF0dW09V0dTODQgK25vX2RlZnMgK2VsbHBzPVdHUzg0ICt0b3dnczg0PTAsMCwwIikKc3BsaXQubGluZSA8LSBTcGF0aWFsTGluZXMobGlzdChMaW5lcyhsaXN0KExpbmUoY2JpbmQoMTgwLXNoaWZ0LGMoLTkwLDkwKSkpKSwgSUQ9ImxpbmUiKSksIAogICAgICAgICAgICAgICAgICAgICAgICAgIHByb2o0c3RyaW5nPVdHUzg0KQoKIyBOT1RFIC0gaW4gY2FzZSBvZiBUb3BvbG9neUV4Y2VwdGlvbicgZXJyb3JzIHdoZW4gaW50ZXJzZWN0aW5nIGxpbmUgd2l0aCBjb3VudHJ5IHBvbHlnb25zLAojIGFwcGx5IHRoZSBnQnVmZmVyIHNvbHV0aW9uIHN1Z2dlc3RlZCBhdDoKIyBodHRwOi8vZ2lzLnN0YWNrZXhjaGFuZ2UuY29tL3F1ZXN0aW9ucy8xNjM0NDUvci1zb2x1dGlvbi1mb3ItdG9wb2xvZ3lleGNlcHRpb24taW5wdXQtZ2VvbS0xLWlzLWludmFsaWQtc2VsZi1pbnRlcnNlY3Rpb24tZXIKTkVfY291bnRyaWVzIDwtIGdCdWZmZXIoTkVfY291bnRyaWVzLCBieWlkPVRSVUUsIHdpZHRoPTApCgojIGludGVyc2VjdGluZyBsaW5lIHdpdGggY291bnRyeSBwb2x5Z29ucwpsaW5lLmdJbnQgPC0gZ0ludGVyc2VjdGlvbihzcGxpdC5saW5lLCBORV9jb3VudHJpZXMpCgojIGNyZWF0ZSBhIHZlcnkgdGhpbiBwb2x5Z29uIChidWZmZXIpIG91dCBvZiB0aGUgaW50ZXJzZWN0aW5nICJzcGxpdCBsaW5lIgpiZiA8LSBnQnVmZmVyKGxpbmUuZ0ludCwgYnlpZD1UUlVFLCB3aWR0aD0wLjAwMDAwMSkgIAoKIyBzcGxpdCBjb3VudHJ5IHBvbHlnb25zIHVzaW5nIGludGVyc2VjdGluZyB0aGluIHBvbHlnb24gKGJ1ZmZlcikKTkVfY291bnRyaWVzLnNwbGl0IDwtIGdEaWZmZXJlbmNlKE5FX2NvdW50cmllcywgYmYsIGJ5aWQ9VFJVRSkKIyBwbG90KE5FX2NvdW50cmllcy5zcGxpdCkgIyBjaGVjayBtYXAKY2xhc3MoTkVfY291bnRyaWVzLnNwbGl0KSAjIGlzIGEgU3BhdGlhbFBvbHlnb25zIG9iamVjdAoKIyB+fn5+fn5+fn5+fiBDcmVhdGUgZ3JhdGljdWxlcyB+fn5+fn5+fn5+fiAjCiMgY3JlYXRlIGEgYm91bmRpbmcgYm94IC0gd29ybGQgZXh0ZW50CmIuYm94IDwtIGFzKHJhc3Rlcjo6ZXh0ZW50KC0xODAsIDE4MCwgLTkwLCA5MCksICJTcGF0aWFsUG9seWdvbnMiKQojIGFzc2lnbiBDUlMgdG8gYm94CnByb2o0c3RyaW5nKGIuYm94KSA8LSBXR1M4NAojIGNyZWF0ZSBncmF0aWN1bGVzL2dyaWQgbGluZXMgZnJvbSBib3gKZ3JpZCA8LSBncmlkbGluZXMoYi5ib3gsIAogICAgICAgICAgICAgICAgICBlYXN0cyAgPSBzZXEoZnJvbT0tMTgwLCB0bz0xODAsIGJ5PTIwKSwKICAgICAgICAgICAgICAgICAgbm9ydGhzID0gc2VxKGZyb209LTkwLCB0bz05MCwgYnk9MTApKQoKIyBjcmVhdGUgbGFiZWxzIGZvciBncmF0aWN1bGVzCmdyaWQubGJsIDwtIGxhYmVscyhncmlkLCBzaWRlID0gMTo0KQoKIyB0cmFuc2Zvcm0gbGFiZWxzIGZyb20gU3BhdGlhbFBvaW50c0RhdGFGcmFtZSB0byBhIGRhdGEgdGFibGUgdGhhdCBnZ3Bsb3QgY2FuIHVzZQpncmlkLmxibC5EVCA8LSBkYXRhLnRhYmxlKGdyaWQubGJsQGNvb3JkcywgZ3JpZC5sYmxAZGF0YSkKCiMgcHJlcGFyZSBsYWJlbHMgd2l0aCByZWd1bGFyIGV4cHJlc3Npb246CiMgLSBkZWxldGUgdW53YW50ZWQgbGFiZWxzCmdyaWQubGJsLkRUWywgbGFiZWxzIDo9IGdzdWIocGF0dGVybj0iMTgwXFwqZGVncmVlfDkwXFwqZGVncmVlXFwqTnw5MFxcKmRlZ3JlZVxcKlMiLCByZXBsYWNlbWVudD0iIiwgeD1sYWJlbHMpXQojIC0gcmVwbGFjZSBwYXR0ZXJuICIqZGVncmVlIiB3aXRoICLCsCIgKCogbmVlZHMgdG8gYmUgZXNjYXBlZCB3aXRoIFxcKQpncmlkLmxibC5EVFssIGxibCA6PSBnc3ViKHBhdHRlcm49IlxcKmRlZ3JlZSIsIHJlcGxhY2VtZW50PSLCsCIsIHg9bGFiZWxzKV0KIyAtIGRlbGV0ZSBhbnkgcmVtYWluaW5nICIqIgpncmlkLmxibC5EVFssIGxibCA6PSBnc3ViKHBhdHRlcm49IipcXCoiLCByZXBsYWNlbWVudD0iIiwgeD1sYmwpXQoKIyBhZGp1c3QgY29vcmRpbmF0ZXMgb2YgbGFiZWxzIHNvIHRoYXQgdGhleSBmaXQgaW5zaWRlIHRoZSBnbG9iZQpncmlkLmxibC5EVFssIGxvbmcgOj0gaWZlbHNlKGNvb3Jkcy54MSAlaW4lIGMoLTE4MCwxODApLCBjb29yZHMueDEqMTc1LzE4MCwgY29vcmRzLngxKV0KZ3JpZC5sYmwuRFRbLCBsYXQgIDo9IGlmZWxzZShjb29yZHMueDIgJWluJSBjKC05MCw5MCksIGNvb3Jkcy54Mio4Mi85MCwgY29vcmRzLngyKV0KCiMgfn5+fn5+fn5+fn4gUHJlcGFyZSBkYXRhIGZvciBnZ3Bsb3QsIHNoaWZ0ICYgcHJvamVjdCBjb29yZGluYXRlcyB+fn5+fn5+fn5+fiAjCiMgZ2l2ZSB0aGUgUE9SSi40IHN0cmluZyBmb3IgRWNrZXJ0IElWIHByb2plY3Rpb24gKCBjaGFuZ2VkIHRvIGRpZmZlcmVudCBwcm9qZWN0aW9uLCAiK3Byb2o9ZWNrNCArbG9uXzA9MCAreF8wPTAgK3lfMD0wICtlbGxwcz1XR1M4NCArZGF0dW09V0dTODQgK3VuaXRzPW0gK25vX2RlZnMiIGZvciBlY2tlcnQpClBST0ogPC0gIitwcm9qPWxvbmdsYXQgK2RhdHVtPVdHUzg0ICtub19kZWZzICtlbGxwcz1XR1M4NCArdG93Z3M4ND0wLDAsMCIgCgojIHRyYW5zZm9ybSBncmF0aWN1bGVzIGZyb20gU3BhdGlhbExpbmVzIHRvIGEgZGF0YSB0YWJsZSB0aGF0IGdncGxvdCBjYW4gdXNlCmdyaWQuRFQgPC0gZGF0YS50YWJsZShtYXBfZGF0YShTcGF0aWFsTGluZXNEYXRhRnJhbWUoc2w9Z3JpZCwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZGF0YT1kYXRhLmZyYW1lKDE6bGVuZ3RoKGdyaWQpKSwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbWF0Y2guSUQgPSBGQUxTRSkpKQojIHByb2plY3QgY29vcmRpbmF0ZXMKIyBhc3NpZ24gbWF0cml4IG9mIHByb2plY3RlZCBjb29yZGluYXRlcyBhcyB0d28gY29sdW1ucyBpbiBkYXRhIHRhYmxlCmdyaWQuRFRbLCBjKCJYIiwiWSIpIDo9IGRhdGEudGFibGUocHJvamVjdChjYmluZChsb25nLCBsYXQpLCBwcm9qPVBST0opKV0KCiMgcHJvamVjdCBjb29yZGluYXRlcyBvZiBsYWJlbHMKZ3JpZC5sYmwuRFRbLCBjKCJYIiwiWSIpIDo9IGRhdGEudGFibGUocHJvamVjdChjYmluZChsb25nLCBsYXQpLCBwcm9qPVBST0opKV0KCiMgdHJhbnNmb3JtIHNwbGl0IGNvdW50cnkgcG9seWdvbnMgaW4gYSBkYXRhIHRhYmxlIHRoYXQgZ2dwbG90IGNhbiB1c2UKQ291bnRyeS5EVF9zaGlmdCA8LSBkYXRhLnRhYmxlKG1hcF9kYXRhKGFzKE5FX2NvdW50cmllcy5zcGxpdCwgIlNwYXRpYWxQb2x5Z29uc0RhdGFGcmFtZSIpKSkKQ291bnRyeS5EVCA8LSBkYXRhLnRhYmxlKG1hcF9kYXRhKGFzKE5FX2NvdW50cmllcywgIlNwYXRpYWxQb2x5Z29uc0RhdGFGcmFtZSIpKSkKIyBTaGlmdCBjb29yZGluYXRlcwpDb3VudHJ5LkRUX3NoaWZ0WywgbG9uZy5uZXcgOj0gbG9uZyArIHNoaWZ0XQpDb3VudHJ5LkRUX3NoaWZ0WywgbG9uZy5uZXcgOj0gaWZlbHNlKGxvbmcubmV3ID4gMTgwLCBsb25nLm5ldy0zNjAsIGxvbmcubmV3KV0KCiMgcHJvamVjdCBjb29yZGluYXRlcyAKQ291bnRyeS5EVFssIGMoIlgiLCJZIikgOj0gZGF0YS50YWJsZShwcm9qZWN0KGNiaW5kKGxvbmcsIGxhdCksIHByb2o9UFJPSikpXQpDb3VudHJ5LkRUX3NoaWZ0WywgYygiWCIsIlkiKSA6PSBkYXRhLnRhYmxlKHByb2plY3QoY2JpbmQobG9uZy5uZXcsIGxhdCksIHByb2o9UFJPSikpXQoKIyB+fn5+fn5+fn5+fiBQbG90IG1hcCB+fn5+fn5+fn5+fiAjCmdncGxvdCgpICsgCiAgICAjIGFkZCBwcm9qZWN0ZWQgY291bnRyaWVzCiAgICBnZW9tX3BvbHlnb24oZGF0YSA9IENvdW50cnkuRFRfc2hpZnQsIAogICAgICAgICAgICAgICAgIGFlcyh4ID0gbG9uZy5uZXcrMTUwLCB5ID0gbGF0LCBncm91cCA9IGdyb3VwKSwgCiAgICAgICAgICAgICAgICAgY29sb3VyID0gImdyYXk3MCIsIAogICAgICAgICAgICAgICAgIGZpbGwgPSAiZ3JheTkwIiwgCiAgICAgICAgICAgICAgICAgc2l6ZSA9IDAuMjUpICsKICAgICMgYWRkIGdyYXRpY3VsZXMKICAgIGdlb21fcGF0aChkYXRhID0gZ3JpZC5EVCwgCiAgICAgICAgICAgICAgYWVzKHggPSBYLCB5ID0gWSwgZ3JvdXAgPSBncm91cCksIAogICAgICAgICAgICAgIGxpbmV0eXBlID0gImRvdHRlZCIsIGNvbG91ciA9ICJncmV5NTAiLCBzaXplID0gLjI1KSArCiAgICAjIGFkZCBhIGJvdW5kaW5nIGJveCAoc2VsZWN0IGdyYXRpY3VsZXMgYXQgZWRnZXMpCiAgICBnZW9tX3BhdGgoZGF0YSA9IGdyaWQuRFRbKGxvbmcgJWluJSBjKC0xODAsMTgwKSAmIHJlZ2lvbiA9PSAiTlMiKQogICAgICAgICAgICAgICAgICAgICAgICAgICAgIHwobG9uZyAlaW4lIGMoLTE4MCwxODApICYgbGF0ICVpbiUgYygtOTAsOTApICYgcmVnaW9uID09ICJFVyIpXSwgCiAgICAgICAgICAgICAgYWVzKHggPSBYLCB5ID0gWSwgZ3JvdXAgPSBncm91cCksIAogICAgICAgICAgICAgIGxpbmV0eXBlID0gInNvbGlkIiwgY29sb3VyID0gImJsYWNrIiwgc2l6ZSA9IC4zKSArCiAgICAjIGFkZCBncmF0aWN1bGUgbGFiZWxzCiAgICBnZW9tX3RleHQoZGF0YSA9IGdyaWQubGJsLkRULCAjIGxhdGl0dWRlCiAgICAgICAgICAgICAgYWVzKHggPSBYLCB5ID0gWSwgbGFiZWwgPSBsYmwpLCAKICAgICAgICAgICAgICBjb2xvdXIgPSAiZ3JleTUwIiwgc2l6ZSA9IDIpICsKICAgICMgZW5zdXJlcyB0aGF0IG9uZSB1bml0IG9uIHRoZSB4LWF4aXMgaXMgdGhlIHNhbWUgbGVuZ3RoIGFzIG9uZSB1bml0IG9uIHRoZSB5LWF4aXMKICAgIGNvb3JkX2VxdWFsKCkgKyAjIHNhbWUgYXMgY29vcmRfZml4ZWQocmF0aW8gPSAxKQogICAgIyBzZXQgZW1wdHkgdGhlbWUKICAgIHRoZW1lX3ZvaWQoKQoKYGBgCgpgYGB7ciBtYXBwaW5nIGVhY2ggcmVnaW9ufQoKcmVnaW9uX21hcHMgPC0gbGlzdCgpCnJlZ2lvbnNfc2hpZnRfcHJvamVjdGlvbiA8LSBjKCJ3ZXN0X3BhY19zcGRmX3NoaWZ0IiwgImVhc3RfcGFjX3NwZGZfc2hpZnQiKQoKCgpmb3IgKGkgaW4gMTpsZW5ndGgocmVnaW9uX25hbWVzKSkgewogIAogIHJlZ2lvbl9zcGRmIDwtIGdldChwYXN0ZTAocmVnaW9uX25hbWVzW2ldLCAiX21hc2siKSkKICAKICBpZihyZWdpb25fbmFtZXNbaV0gJWluJSByZWdpb25zX3NoaWZ0X3Byb2plY3Rpb24pIHsKICAKICAjcGFjaWZpYyBjZW50ZXJlZCBwcm9qZWN0aW9uCiAgCiAgcmVnaW9uX3NwZGZfbWFza18xc19leHRlbnQgPC0gZXh0ZW50KGdldChwYXN0ZTAocmVnaW9uX25hbWVzW2ldLCJfbWFza18xcyIpKSkgIyB0YWtlIGV4dGVudCBvZiByZWdpb24KICAKICAjY29udmVydCByYXN0ZXJzIHRvIGRmcyBkYXRhIGZyYW1lCiAgcmVnaW9uX3NwZGYgPC0gYXMoZ2V0KHBhc3RlMChyZWdpb25fbmFtZXNbaV0sIl9tYXNrXzFzIikpLCAiU3BhdGlhbFBpeGVsc0RhdGFGcmFtZSIpCiAgcmVnaW9uX2RmIDwtIGFzLmRhdGEuZnJhbWUocmVnaW9uX3NwZGYpCiAgY29sbmFtZXMocmVnaW9uX2RmKSA8LSBjKCJ2YWx1ZSIsICJ4IiwgInkiKQogIAogIAogIChyZWdpb25fbWFwc1tbaV1dIDwtIGdncGxvdCgpICsgCiAgICAjIGFkZCBwcm9qZWN0ZWQgY291bnRyaWVzCiAgICBnZW9tX3BvbHlnb24oZGF0YSA9IENvdW50cnkuRFRfc2hpZnQsIAogICAgICAgICAgICAgICAgIGFlcyh4ID0gbG9uZy5uZXcrMTUwLCB5ID0gbGF0LCBncm91cCA9IGdyb3VwKSwgCiAgICAgICAgICAgICAgICAgY29sb3VyID0gImdyYXk3MCIsIAogICAgICAgICAgICAgICAgIGZpbGwgPSAiZ3JheTkwIiwgCiAgICAgICAgICAgICAgICAgc2l6ZSA9IDAuMjUpICsKICAgIGdlb21fdGlsZShkYXRhID0gcmVnaW9uX2RmLCBhZXMoeCA9IHgsIHkgPSB5LCBmaWxsID0gdmFsdWUpLCBjb2xvciA9ICJzZWFncmVlbjQiKSArCiAgICBjb29yZF9zZih4ID0gYyhyZWdpb25fc3BkZl9tYXNrXzFzX2V4dGVudFsxXSwgcmVnaW9uX3NwZGZfbWFza18xc19leHRlbnRbMl0pLCB5ID0gYyhyZWdpb25fc3BkZl9tYXNrXzFzX2V4dGVudFszXSwgcmVnaW9uX3NwZGZfbWFza18xc19leHRlbnRbNF0pKSArCiAgICBsYWJzKCB4ID0gZXhwcmVzc2lvbigiTG9uZ2l0dWRlICgiKn5kZWdyZWUqRSoiKSIpLCB5ID0gZXhwcmVzc2lvbigiTGF0aXR1ZGUgKCIqfmRlZ3JlZSpOKiIpIikpICsKICAgIGdlb21fYWJsaW5lKGludGVyY2VwdCA9IDAsIHNsb3BlID0gMCkgKwogICAgdGhlbWVfY2xhc3NpYygpICsKICAgIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbiA9ICJub25lIikpCiAgCiAgZmlsZW5hbWUgPC0gcGFzdGUwKHJlZ2lvbl9uYW1lc1tpXSwgIl9tYXAuanBnIikKICBnZ3NhdmUocGxvdCA9IHJlZ2lvbl9tYXBzW1tpXV0sIGZpbGVuYW1lID0gZmlsZW5hbWUsIGhlaWdodCA9IDQsIHVuaXRzID0gYygiaW4iKSkKICAKICB9IGVsc2UgewoKICAjYXRsYW50aWMgY2VudGVyZWQgcHJvamVjdGlvbgogIHJlZ2lvbl9zcGRmX21hc2tfMXNfZXh0ZW50IDwtIGV4dGVudChnZXQocGFzdGUwKHJlZ2lvbl9uYW1lc1tpXSwiX21hc2tfMXMiKSkpICMgdGFrZSBleHRlbnQgb2YgcmVnaW9uCiAgCiAgI2NvbnZlcnQgcmFzdGVycyB0byBkZnMgZGF0YSBmcmFtZQogIHJlZ2lvbl9zcGRmIDwtIGFzKGdldChwYXN0ZTAocmVnaW9uX25hbWVzW2ldLCJfbWFza18xcyIpKSwgIlNwYXRpYWxQaXhlbHNEYXRhRnJhbWUiKQogIHJlZ2lvbl9kZiA8LSBhcy5kYXRhLmZyYW1lKHJlZ2lvbl9zcGRmKQogIGNvbG5hbWVzKHJlZ2lvbl9kZikgPC0gYygidmFsdWUiLCAieCIsICJ5IikKICAKICAKICAocmVnaW9uX21hcHNbW2ldXSA8LSBnZ3Bsb3QoKSArIAogICAgIyBhZGQgcHJvamVjdGVkIGNvdW50cmllcwogICAgZ2VvbV9wb2x5Z29uKGRhdGEgPSBDb3VudHJ5LkRULCAKICAgICAgICAgICAgICAgICBhZXMoeCA9IGxvbmcsIHkgPSBsYXQsIGdyb3VwID0gZ3JvdXApLCAKICAgICAgICAgICAgICAgICBjb2xvdXIgPSAiZ3JheTcwIiwgCiAgICAgICAgICAgICAgICAgZmlsbCA9ICJncmF5OTAiLCAKICAgICAgICAgICAgICAgICBzaXplID0gMC4yNSkgKwogICAgZ2VvbV90aWxlKGRhdGEgPSByZWdpb25fZGYsIGFlcyh4ID0geCwgeSA9IHksIGZpbGwgPSB2YWx1ZSksIGNvbG9yID0gInNlYWdyZWVuNCIpICsKICAgIGNvb3JkX3NmKHggPSBjKHJlZ2lvbl9zcGRmX21hc2tfMXNfZXh0ZW50WzFdLCByZWdpb25fc3BkZl9tYXNrXzFzX2V4dGVudFsyXSksIHkgPSBjKHJlZ2lvbl9zcGRmX21hc2tfMXNfZXh0ZW50WzNdLCByZWdpb25fc3BkZl9tYXNrXzFzX2V4dGVudFs0XSkpICsKICAgIGxhYnMoIHggPSBleHByZXNzaW9uKCJMb25naXR1ZGUgKCIqfmRlZ3JlZSpFKiIpIiksIHkgPSBleHByZXNzaW9uKCJMYXRpdHVkZSAoIip+ZGVncmVlKk4qIikiKSkgKwogICAgZ2VvbV9hYmxpbmUoaW50ZXJjZXB0ID0gMCwgc2xvcGUgPSAwKSArCiAgICB0aGVtZV9jbGFzc2ljKCkgKwogICAgdGhlbWUobGVnZW5kLnBvc2l0aW9uID0gIm5vbmUiKSkKICAKICBmaWxlbmFtZSA8LSBwYXN0ZTAocmVnaW9uX25hbWVzW2ldLCAiX21hcC5qcGciKQogIGdnc2F2ZShwbG90ID0gcmVnaW9uX21hcHNbW2ldXSwgZmlsZW5hbWUgPSBmaWxlbmFtZSwgaGVpZ2h0ID0gNCwgdW5pdHMgPSBjKCJpbiIpKQogIAogIH0KICAKICB9CmBgYAoKQ29tYmluaW5nIHBsb3RzCgpyZWdpb25fbWFwczogCiJ3ZXN0X3BhY19zcGRmX3NoaWZ0IiwgCiJlYXN0X3BhY19zcGRmX3NoaWZ0IiwgCiJ3ZXN0X2F0bF9zcGRmIiwgCiJ3ZXN0X2luZF9zcGRmIiwgCiJlYXN0X2F0bF9zcGRmX25vYnVmIiwgCiJlYXN0X2luZF9zcGRmIgoKUGxvdHMgb2YgYXJlYSB2ZXJzdXMgbGF0aXR1ZGUKYXJlYV9sYXRpdHVkZV9lYXN0X3BhYwoKTm93LCBjb21iaW5lIHBsb3RzCgpgYGB7ciBjb21iaW5pbmcgcGxvdHN9CmxpYnJhcnkoZWdnKQpsaWJyYXJ5KGdncHVicikKCiN3ZXN0IHBhY2lmaWMKKHdlc3RfcGFjaWZpY19tZXJnZV9tYXBfcGxvdCA8LSBlZ2c6OmdnYXJyYW5nZShyZWdpb25fbWFwc1tbMV1dLCAKICAgICAgICAgIGFyZWFfbGF0aXR1ZGVfd2VzdF9wYWMgCiAgICAgICAgICArIAogICAgICAgICAgICAgICB0aGVtZShheGlzLnRleHQueSA9IGVsZW1lbnRfYmxhbmsoKSwKICAgICAgICAgICAgICAgICAgICAgYXhpcy50aWNrcy55ID0gZWxlbWVudF9ibGFuaygpLAogICAgICAgICAgICAgICAgICAgICBheGlzLnRpdGxlLnkgPSBlbGVtZW50X2JsYW5rKCkgKSwgCgogICAgICAgICAgbnJvdyA9IDEsCiAgICAgICAgICB0b3AgPSBUKSkKCmdnc2F2ZShwbG90ID0gd2VzdF9wYWNpZmljX21lcmdlX21hcF9wbG90LCBmaWxlbmFtZSA9ICJ3ZXN0X3BhY2lmaWNfbWVyZ2VfbWFwX3Bsb3QuanBnIiwgd2lkdGggPSA3LCBoZWlnaHQgPSAzLCB1bml0cyA9ICJpbiIpCgojZWFzdCBwYWNpZmljCihlYXN0X3BhY2lmaWNfbWVyZ2VfbWFwX3Bsb3QgPC0gZWdnOjpnZ2FycmFuZ2UocmVnaW9uX21hcHNbWzJdXSwgCiAgICAgICAgICBhcmVhX2xhdGl0dWRlX2Vhc3RfcGFjIAogICAgICAgICAgKyAKICAgICAgICAgICAgICAgdGhlbWUoYXhpcy50ZXh0LnkgPSBlbGVtZW50X2JsYW5rKCksCiAgICAgICAgICAgICAgICAgICAgIGF4aXMudGlja3MueSA9IGVsZW1lbnRfYmxhbmsoKSwKICAgICAgICAgICAgICAgICAgICAgYXhpcy50aXRsZS55ID0gZWxlbWVudF9ibGFuaygpICkKICAgICAgICAgICwgCgogICAgICAgICAgbnJvdyA9IDEsCiAgICAgICAgICB0b3AgPSBUKSkKCmdnc2F2ZShwbG90ID0gZWFzdF9wYWNpZmljX21lcmdlX21hcF9wbG90LCBmaWxlbmFtZSA9ICJlYXN0X3BhY2lmaWNfbWVyZ2VfbWFwX3Bsb3QuanBnIiwgd2lkdGggPSA3LCBoZWlnaHQgPSAzLCB1bml0cyA9ICJpbiIpCgoKI3dlc3QgYXRsYW50aWMKKHdlc3RfYXRsYW50aWNfbWVyZ2VfbWFwX3Bsb3QgPC0gZWdnOjpnZ2FycmFuZ2UocmVnaW9uX21hcHNbWzNdXSwgCiAgICAgICAgICBhcmVhX2xhdGl0dWRlX3dlc3RfYXRsCiAgICAgICAgICArIAogICAgICAgICAgICAgICB0aGVtZShheGlzLnRleHQueSA9IGVsZW1lbnRfYmxhbmsoKSwKICAgICAgICAgICAgICAgICAgICAgYXhpcy50aWNrcy55ID0gZWxlbWVudF9ibGFuaygpLAogICAgICAgICAgICAgICAgICAgICBheGlzLnRpdGxlLnkgPSBlbGVtZW50X2JsYW5rKCkgKQogICAgICAgICAgLCAKCiAgICAgICAgICBucm93ID0gMSwKICAgICAgICAgIHRvcCA9IFQpKQoKZ2dzYXZlKHBsb3QgPSB3ZXN0X2F0bGFudGljX21lcmdlX21hcF9wbG90LCBmaWxlbmFtZSA9ICJ3ZXN0X2F0bGFudGljX21lcmdlX21hcF9wbG90LmpwZyIsIHdpZHRoID0gNywgaGVpZ2h0ID0gMywgdW5pdHMgPSAiaW4iKQoKI3dlc3QgaW5kaWFuCih3ZXN0X2luZGlhbl9tZXJnZV9tYXBfcGxvdCA8LSBlZ2c6OmdnYXJyYW5nZShyZWdpb25fbWFwc1tbNF1dLCAKICAgICAgICAgIGFyZWFfbGF0aXR1ZGVfd2VzdF9pbmQgCiAgICAgICAgICArIAogICAgICAgICAgICAgICB0aGVtZShheGlzLnRleHQueSA9IGVsZW1lbnRfYmxhbmsoKSwKICAgICAgICAgICAgICAgICAgICAgYXhpcy50aWNrcy55ID0gZWxlbWVudF9ibGFuaygpLAogICAgICAgICAgICAgICAgICAgICBheGlzLnRpdGxlLnkgPSBlbGVtZW50X2JsYW5rKCkgKQogICAgICAgICAgLCAKCiAgICAgICAgICBucm93ID0gMSwKICAgICAgICAgIHRvcCA9IFQpKQoKZ2dzYXZlKHBsb3QgPSB3ZXN0X2luZGlhbl9tZXJnZV9tYXBfcGxvdCwgZmlsZW5hbWUgPSAid2VzdF9pbmRpYW5fbWVyZ2VfbWFwX3Bsb3QuanBnIiwgd2lkdGggPSA3LCBoZWlnaHQgPSAzLCB1bml0cyA9ICJpbiIpCgojZWFzdCBhdGxhbnRpYwooZWFzdF9hdGxhbnRpY19tZXJnZV9tYXBfcGxvdCA8LSBlZ2c6OmdnYXJyYW5nZShyZWdpb25fbWFwc1tbNV1dLCAKICAgICAgICAgIGFyZWFfbGF0aXR1ZGVfZWFzdF9hdGwKICAgICAgICAgICsgCiAgICAgICAgICAgICAgIHRoZW1lKGF4aXMudGV4dC55ID0gZWxlbWVudF9ibGFuaygpLAogICAgICAgICAgICAgICAgICAgICBheGlzLnRpY2tzLnkgPSBlbGVtZW50X2JsYW5rKCksCiAgICAgICAgICAgICAgICAgICAgIGF4aXMudGl0bGUueSA9IGVsZW1lbnRfYmxhbmsoKSApCiAgICAgICAgICAsIAoKICAgICAgICAgIG5yb3cgPSAxLAogICAgICAgICAgdG9wID0gVCkpCgpnZ3NhdmUocGxvdCA9IGVhc3RfYXRsYW50aWNfbWVyZ2VfbWFwX3Bsb3QsIGZpbGVuYW1lID0gImVhc3RfYXRsYW50aWNfbWVyZ2VfbWFwX3Bsb3QuanBnIiwgd2lkdGggPSA3LCBoZWlnaHQgPSAzLCB1bml0cyA9ICJpbiIpCgojZWFzdCBpbmRpYW4KKGVhc3RfaW5kaWFuX21lcmdlX21hcF9wbG90IDwtIGVnZzo6Z2dhcnJhbmdlKHJlZ2lvbl9tYXBzW1s2XV0sIAogICAgICAgICAgYXJlYV9sYXRpdHVkZV9lYXN0X2luZAogICAgICAgICAgKyAKICAgICAgICAgICAgICAgdGhlbWUoYXhpcy50ZXh0LnkgPSBlbGVtZW50X2JsYW5rKCksCiAgICAgICAgICAgICAgICAgICAgIGF4aXMudGlja3MueSA9IGVsZW1lbnRfYmxhbmsoKSwKICAgICAgICAgICAgICAgICAgICAgYXhpcy50aXRsZS55ID0gZWxlbWVudF9ibGFuaygpICkKICAgICAgICAgICwgCgogICAgICAgICAgbnJvdyA9IDEsCiAgICAgICAgICB0b3AgPSBUKSkKCmdnc2F2ZShwbG90ID0gZWFzdF9pbmRpYW5fbWVyZ2VfbWFwX3Bsb3QsIGZpbGVuYW1lID0gImVhc3RfaW5kaWFuX21lcmdlX21hcF9wbG90LmpwZyIsIHdpZHRoID0gNywgaGVpZ2h0ID0gMywgdW5pdHMgPSAiaW4iKQpgYGAKCgpNYWtlIG1hcCBvZiB3b3JsZAoKRWFjaCByZWdpb24gY29kZWQgd2l0aCAjIGV4cGFuc2lvbnMgYW5kICMgY29udHJhY3Rpb25zCgpgYGB7cn0KCnNhdmUoc2lnbmlmaWNhbnRfY2hhbmdlcy5sb25nLCBzaWduaWZpY2FudF9jaGFuZ2VzLCBmaWxlID0gInNpZ25pZmljYW50X2NoYW5nZXMuUkRhdGEiKQoKYGBgCgo=